import { JSX, useEffect, useState } from "react";
import styles from "./Calendar.module.css";
import { getMonthName, daysInMonth } from "../utils/dateUtils";
import { customerState } from "../store";
import { Box } from "../types";
import { useAtom } from "jotai";
import { markBoxDelivered, markBoxPickedUp } from "../api";
import { Modal } from "@mui/material";

export default function Calendar() {
    const boxStatuses = ["no boxes", "picked up", "delivered"]; //TODO: There's logic problem between "delivered" and "picked up"
    const [customerData, setCustomerData] = useAtom(customerState);
    const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth());
    const [calendarCells, setCalendarCells] = useState<JSX.Element[]>([]);
    const [firstWeekPadding, setFirstWeekPadding] = useState<JSX.Element[]>([]);
    const [showLatestBoxModal, setShowLatestBoxModal] = useState(false);
    const [latestBoxStatus, setLatestBoxStatus] = useState<string>(boxStatuses[0]);
    const [latestBox, setLatestBox] = useState<Box>({
        id: "",
        pickup_date: null,
        delivery_date: new Date(),
    });
    const [showClickedBoxModal, setShowClickedBoxModal] = useState(false);
    const [clickedBox, setClickedBox] = useState<Box>({
        id: "",
        pickup_date: null,
        delivery_date: new Date(),
    });

    const generateFirstWeekPadding = (month: number) => {
        const firstDay = new Date(new Date().getFullYear(), month, 1).getDay();
        const padding = Array.from({ length: firstDay === 0 ? 6 : firstDay - 1 }, (_, index) => (
            <div key={index}>
                &nbsp;
            </div>
        ));
        return padding;
    }

    const generateCalendarCells = (month: number, boxes: Box[]) => {
        const monthDays = daysInMonth[month];

        const calendarCells = Array.from({ length: monthDays }, (_, index) => {
            const day = index + 1;
            const date = new Date(new Date().getFullYear(), month, day);
            const matchingBox = boxes.find(box => {
                const boxDate = new Date(box.delivery_date);
                return boxDate.getDate() === day && boxDate.getMonth() === month && boxDate.getFullYear() === date.getFullYear();
            });

            if (matchingBox) {
                return (
                    <div
                        key={index}
                        className={`${styles.calendarCell} ${matchingBox.pickup_date ? styles.pickedUpCell : styles.deliveredCell}`}
                        onClick={() => {
                            setClickedBox(matchingBox);
                            setShowClickedBoxModal(true);
                        }
                        }>
                        {
                            date.toLocaleDateString("fi-FI", {
                                day: "2-digit",
                                month: "2-digit",
                            })
                        }
                        < br />
                        {
                            matchingBox.pickup_date ? (
                                <span className={styles.statusText}>Haettu</span>
                            ) : (
                                <span className={styles.statusText}>Jako</span>
                            )
                        }
                    </div >
                );
            }

            return (
                <div key={index} className={`${styles.calendarCell}`}>
                    {date.toLocaleDateString("fi-FI", {
                        day: "2-digit",
                        month: "2-digit",
                    })}
                </div>
            );
        });
        return calendarCells;
    }

    const changeClickedBoxStatus = () => {
        if (clickedBox.pickup_date) {
            // If the box is already picked up, mark it as delivered
            markBoxDelivered(clickedBox.id).then((updatedBox) => {
                setCustomerData((prev) => ({
                    ...prev,
                    boxes: prev.boxes.map(box =>
                        box.id === updatedBox.id ? { ...box, pickup_date: null } : box
                    ),
                }));
            }
            ).catch((error) => {
                console.error("Error marking box as delivered:", error);
            });
            return;
        } else {
            markBoxPickedUp(clickedBox.id).then((updatedBox) => {
                setCustomerData((prev) => ({
                    ...prev,
                    boxes: prev.boxes.map(box =>
                        box.id === updatedBox.id ? { ...box, pickup_date: updatedBox.pickup_date } : box
                    ),
                }));
            }
            ).catch((error) => {
                console.error("Error marking box as picked up:", error);
            })
        }
    }

    const renderLatestBoxButton = () => {
        switch (latestBoxStatus) {
            case "no boxes":
                return <button
                    className={styles.latestBoxNoBoxesBtn}
                    disabled
                >
                    Ei laatikoita tässä kuussa
                </button>;
            case "picked up":
                return <button
                    className={styles.latestBoxPickedUpBtn}
                    disabled
                >
                    Uusin laatikko on jo haettu
                </button>;
            case "delivered":
                return <button
                    className={styles.latestBoxDeliveredBtn}
                    onClick={handleLatestBoxClick}
                >
                    Kuittaa {new Date(latestBox.delivery_date).toLocaleDateString("fi-FI", {
                        day: "2-digit",
                        month: "2-digit",
                    })} laatikko haetuksi
                </button>;
            default:
                return <span className={styles.latestBoxStatus}>Virhe</span>;
        }
    }

    useEffect(() => {
        setCalendarCells(generateCalendarCells(selectedMonth, customerData.boxes));
        setFirstWeekPadding(generateFirstWeekPadding(selectedMonth));
        setLatestBoxStatus(() => {
            if (!customerData.boxes || customerData.boxes.length === 0) {
                return boxStatuses[0]; // no boxes
            }
            const monthBoxes = customerData.boxes.filter(box => new Date(box.delivery_date).getMonth() === selectedMonth);
            const deliveredBoxes = customerData.boxes.filter(box => new Date(box.delivery_date).getMonth() === selectedMonth && !box.pickup_date);
            if (monthBoxes.length === 0) {
                return boxStatuses[0]; // no boxes
            }
            if (!deliveredBoxes || deliveredBoxes.length === 0) {
                return boxStatuses[1]; // all boxes picked up
            }
            return boxStatuses[2]; // delivered
        }
        );
    }, [selectedMonth, customerData.boxes]);

    const handleLatestBoxClick = (event: React.MouseEvent<HTMLButtonElement>) => {
        event.preventDefault();
        setShowLatestBoxModal(true);
    }

    const markLatestBoxPickedUp = () => {
        markBoxPickedUp(latestBox.id).then((updatedBox) => {
            setCustomerData((prev) => ({
                ...prev,
                boxes: prev.boxes.map(box =>
                    box.id === updatedBox.id ? { ...box, pickup_date: updatedBox.pickup_date } : box
                ),
            }));
        }).catch((error) => {
            console.error("Error marking latest box as picked up:", error);
        });
    }

    useEffect(() => {
        const deliveredBoxes = customerData.boxes.filter(box => new Date(box.delivery_date).getMonth() === selectedMonth && !box.pickup_date);
        if (deliveredBoxes.length === 0) return;
        const latestBox = deliveredBoxes[0];

        if (latestBox) {
            setLatestBox(latestBox);
        }
    }, [customerData.boxes, selectedMonth]);

    return (
        <>
            <h2 className={styles.monthTitle}>
                {getMonthName(selectedMonth)} {new Date().getFullYear()}
            </h2>
            <div className={styles.monthNavigation}>
                <button onClick={() => setSelectedMonth((prev) => (prev - 1 + 12) % 12)} className={styles.monthNavBtn}>
                    &lt; Edellinen kuukausi
                </button>
                <button onClick={() => setSelectedMonth((prev) => (prev + 1) % 12)} className={styles.monthNavBtn}>
                    Seuraava kuukausi &gt;
                </button>
            </div>
            <div className={styles.latestBoxBtnContainer}>
                {renderLatestBoxButton()}
            </div>
            <div className={styles.guideText}>
                <h3>Käyttöohje</h3>
                Klikkaa laatikon päivää kuitataksesi sen haetuksi tai peruuttaaksesi haun.
                Jakopäivät näkyvät vaalean vihreinä. Jos laatikko on jo haettu, se näkyy tumman vihreänä.
            </div>
            <div className={styles.calendarGrid}>
                <span>Ma</span>
                <span>Ti</span>
                <span>Ke</span>
                <span>To</span>
                <span>Pe</span>
                <span>La</span>
                <span>Su</span>
                {firstWeekPadding}
                {calendarCells}
            </div>
            <Modal
                open={showLatestBoxModal}
                onClose={() => setShowLatestBoxModal(false)}
                className={styles.boxModal}
            >
                <div className={styles.boxModalContent}>
                    <h2>Viimeisin laatikko</h2>
                    <p>Oletko varma, että haluat kuitata viimeisimmän laatikon ({new Date(latestBox.delivery_date).toLocaleDateString("fi-FI", {
                        day: "2-digit",
                        month: "2-digit",
                    })}) haetuksi?</p>
                    <button
                        className={styles.boxModalConfirmButton}
                        onClick={() => {
                            markLatestBoxPickedUp();
                            setShowLatestBoxModal(false);
                        }}
                    >
                        Kyllä
                    </button>
                    <button
                        className={styles.boxModalCancelButton}
                        onClick={() => setShowLatestBoxModal(false)}
                    >
                        Peruuta
                    </button>
                </div>
            </Modal>
            <Modal
                open={showClickedBoxModal}
                onClose={() => setShowClickedBoxModal(false)}
                className={styles.boxModal}
            >
                <div className={styles.boxModalContent}>
                    <h2>Satolaatikko {" "}
                        {new Date(clickedBox.delivery_date).toLocaleDateString("fi-FI", {
                            day: "2-digit",
                            month: "2-digit",
                        })}
                    </h2>
                    <p>Oletko varma, että haluat {clickedBox.pickup_date ? "peruuttaa " : "kuitata "}
                        {new Date(clickedBox.delivery_date).toLocaleDateString("fi-FI", {
                            day: "2-digit",
                            month: "2-digit",
                        })} päivän laatikon {clickedBox.pickup_date ? "haun" : "haetuksi"}?</p>
                    <button
                        className={styles.boxModalConfirmButton}
                        onClick={() => {
                            changeClickedBoxStatus();
                            setShowClickedBoxModal(false);
                        }}
                    >
                        Kyllä
                    </button>
                    <button
                        className={styles.boxModalCancelButton}
                        onClick={() => setShowClickedBoxModal(false)}
                    >
                        Peruuta
                    </button>
                </div>
            </Modal >
        </>
    );
}