"use client";

import {
    useCallback,
    useEffect,
    useMemo,
    useState,
    type MouseEvent,
} from "react";

import CheckBoxOutlineBlankRoundedIcon from "@mui/icons-material/CheckBoxOutlineBlankRounded";
import CheckBoxRoundedIcon from "@mui/icons-material/CheckBoxRounded";
import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded";
import KeyboardArrowDownRoundedIcon from "@mui/icons-material/KeyboardArrowDownRounded";
import KeyboardArrowUpRoundedIcon from "@mui/icons-material/KeyboardArrowUpRounded";

import {
    Box,
    Button,
    Checkbox,
    CircularProgress,
    Divider,
    Menu,
    MenuItem,
    Typography,
} from "@mui/material";
import { alpha, useTheme } from "@mui/material/styles";

import type { MinistryRgcDecisionStatus } from "../data/ministry-rgc-decision-data";

const API_BASE_URL =
    process.env.NEXT_PUBLIC_API_URL?.replace(/\/$/, "") ??
    "http://localhost:3001/api/v1";

const STATUS_OPTIONS: MinistryRgcDecisionStatus[] = [
    "Not Addressed",
    "In Progress",
    "Solved",
];

const MONTH_OPTIONS = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
] as const;

type FilterKey =
    | "status"
    | "primaryAgency"
    | "category"
    | "meetingDate";

type LookupOption = {
    id: number;
    label: string;
};

type ApiLookupItem = {
    id?: number | string;
    name?: string | null;
    label?: string | null;
};

type ApiResponse = {
    message?: string | string[];

    data?:
    | ApiLookupItem[]
    | {
        items?: ApiLookupItem[];
        data?: ApiLookupItem[];
    };

    items?: ApiLookupItem[];
};

type Props = {
    selectedStatuses: MinistryRgcDecisionStatus[];
    selectedPrimaryAgencyIds: number[];
    selectedCategoryIds: number[];
    meetingDate: string;

    onToggleStatus: (
        status: MinistryRgcDecisionStatus,
    ) => void;

    onTogglePrimaryAgency: (id: number) => void;
    onToggleCategory: (id: number) => void;

    onSelectAllStatuses: (
        all: MinistryRgcDecisionStatus[],
    ) => void;

    onSelectAllPrimaryAgencies: (
        all: number[],
    ) => void;

    onSelectAllCategories: (
        all: number[],
    ) => void;

    onMeetingDateChange: (value: string) => void;
    onReset: () => void;
};

function parseMeetingMonth(value: string) {
    const match = /^(\d{4})-(\d{2})$/.exec(value);

    if (match) {
        const year = Number(match[1]);
        const month = Number(match[2]) - 1;

        if (
            Number.isInteger(year) &&
            Number.isInteger(month) &&
            month >= 0 &&
            month <= 11
        ) {
            return {
                year,
                month,
            };
        }
    }

    const now = new Date();

    return {
        year: now.getFullYear(),
        month: now.getMonth(),
    };
}

function formatMeetingMonth(
    month: number,
    year: number,
) {
    return `${year}-${String(month + 1).padStart(2, "0")}`;
}

function getAccessToken(): string {
    if (typeof window === "undefined") {
        return "";
    }

    return (
        localStorage.getItem("accessToken") ||
        localStorage.getItem("access_token") ||
        localStorage.getItem("authToken") ||
        localStorage.getItem("token") ||
        localStorage.getItem("gpsf_access_token") ||
        sessionStorage.getItem("accessToken") ||
        sessionStorage.getItem("access_token") ||
        sessionStorage.getItem("authToken") ||
        sessionStorage.getItem("token") ||
        ""
    );
}

function extractItems(
    payload: ApiResponse,
): ApiLookupItem[] {
    if (Array.isArray(payload.data)) {
        return payload.data;
    }

    if (
        payload.data &&
        typeof payload.data === "object"
    ) {
        if (Array.isArray(payload.data.items)) {
            return payload.data.items;
        }

        if (Array.isArray(payload.data.data)) {
            return payload.data.data;
        }
    }

    return Array.isArray(payload.items)
        ? payload.items
        : [];
}

async function fetchLookup(
    endpoint: string,
): Promise<LookupOption[]> {
    const token = getAccessToken();

    const response = await fetch(
        `${API_BASE_URL}${endpoint}`,
        {
            method: "GET",
            credentials: "include",
            cache: "no-store",
            headers: {
                Accept: "application/json",
                ...(token
                    ? {
                        Authorization: `Bearer ${token}`,
                    }
                    : {}),
            },
        },
    );

    const payload = (await response.json()) as ApiResponse;

    if (!response.ok) {
        const message = Array.isArray(payload.message)
            ? payload.message.join(", ")
            : payload.message ||
            "Unable to load filter options.";

        throw new Error(message);
    }

    return extractItems(payload)
        .map((item) => ({
            id: Number(item.id),
            label:
                item.name?.trim() ||
                item.label?.trim() ||
                "",
        }))
        .filter(
            (item) =>
                Number.isInteger(item.id) &&
                item.id > 0 &&
                item.label.length > 0,
        );
}

function FilterButton({
    label,
    open,
    width,
    onClick,
}: {
    label: string;
    open: boolean;
    width: number;
    onClick: (
        event: MouseEvent<HTMLButtonElement>,
    ) => void;
}) {
    const theme = useTheme();

    return (
        <Button
            variant="outlined"
            onClick={onClick}
            endIcon={
                <ExpandMoreRoundedIcon
                    sx={{
                        transform: open
                            ? "rotate(180deg)"
                            : "none",
                        transition: "transform 160ms ease",
                    }}
                />
            }
            sx={{
                width,
                height: 40,
                px: 1.5,
                justifyContent: "space-between",
                flexShrink: 0,
                borderRadius: "6px",
                textTransform: "none",
                color: theme.palette.text.secondary,
                bgcolor: theme.palette.background.paper,
                borderColor: open
                    ? theme.palette.primary.main
                    : theme.palette.divider,
                fontSize: 13,
                fontWeight: 500,

                "&:hover": {
                    borderColor: theme.palette.primary.main,
                    bgcolor: alpha(
                        theme.palette.primary.main,
                        0.04,
                    ),
                },
            }}
        >
            <Box
                component="span"
                sx={{
                    minWidth: 0,
                    overflow: "hidden",
                    textOverflow: "ellipsis",
                    whiteSpace: "nowrap",
                }}
            >
                {label}
            </Box>
        </Button>
    );
}

function CheckOption({
    label,
    checked,
    indeterminate = false,
    onClick,
}: {
    label: string;
    checked: boolean;
    indeterminate?: boolean;
    onClick: () => void;
}) {
    const theme = useTheme();

    return (
        <MenuItem
            onClick={onClick}
            sx={{
                minHeight: 40,
                gap: 1,
                px: 1,
                mx: 0.5,
                borderRadius: "5px",

                "&:hover": {
                    bgcolor: alpha(
                        theme.palette.primary.main,
                        0.07,
                    ),
                },
            }}
        >
            <Checkbox
                checked={checked}
                indeterminate={indeterminate}
                icon={
                    <CheckBoxOutlineBlankRoundedIcon
                        sx={{ fontSize: 19 }}
                    />
                }
                checkedIcon={
                    <CheckBoxRoundedIcon
                        sx={{ fontSize: 19 }}
                    />
                }
                sx={{ p: 0 }}
            />

            <Typography
                sx={{
                    fontSize: 13,
                    fontWeight: 500,
                }}
            >
                {label}
            </Typography>
        </MenuItem>
    );
}

export function MinistryRgcDecisionFilters({
    selectedStatuses,
    selectedPrimaryAgencyIds,
    selectedCategoryIds,
    meetingDate,

    onToggleStatus,
    onTogglePrimaryAgency,
    onToggleCategory,

    onSelectAllStatuses,
    onSelectAllPrimaryAgencies,
    onSelectAllCategories,

    onMeetingDateChange,
    onReset,
}: Props) {
    const theme = useTheme();

    const [anchorEl, setAnchorEl] =
        useState<HTMLElement | null>(null);

    const [activeFilter, setActiveFilter] =
        useState<FilterKey | null>(null);

    const [ministries, setMinistries] =
        useState<LookupOption[]>([]);

    const [categories, setCategories] =
        useState<LookupOption[]>([]);

    const [loading, setLoading] = useState(true);

    const [lookupError, setLookupError] =
        useState<string | null>(null);

    /*
     * Initialize draft date once.
     * It will be synchronized when the Meeting Date menu opens,
     * instead of synchronizing inside an effect.
     */
    const initialMeetingDate =
        parseMeetingMonth(meetingDate);

    const [draftMonth, setDraftMonth] =
        useState(initialMeetingDate.month);

    const [draftYear, setDraftYear] =
        useState(initialMeetingDate.year);

    const loadLookups = useCallback(async () => {
        setLoading(true);
        setLookupError(null);

        try {
            const [agencyItems, categoryItems] =
                await Promise.all([
                    fetchLookup(
                        "/rgc-decisions/lookups/ministries",
                    ),
                    fetchLookup(
                        "/rgc-decisions/lookups/categories",
                    ),
                ]);

            setMinistries(agencyItems);
            setCategories(categoryItems);
        } catch (requestError) {
            setMinistries([]);
            setCategories([]);

            setLookupError(
                requestError instanceof Error
                    ? requestError.message
                    : "Unable to load filter options.",
            );
        } finally {
            setLoading(false);
        }
    }, []);

    /*
     * Do not call loadLookups synchronously in the effect.
     * Schedule it in a callback to satisfy React lint rules.
     */
    useEffect(() => {
        const timeoutId = window.setTimeout(() => {
            void loadLookups();
        }, 0);

        return () => {
            window.clearTimeout(timeoutId);
        };
    }, [loadLookups]);

    const openMenu = (
        key: FilterKey,
        event: MouseEvent<HTMLButtonElement>,
    ) => {
        /*
         * Sync the draft month/year in the user event handler.
         * This replaces the old useEffect that called setState.
         */
        if (key === "meetingDate") {
            const next = parseMeetingMonth(meetingDate);

            setDraftMonth(next.month);
            setDraftYear(next.year);
        }

        setActiveFilter(key);
        setAnchorEl(event.currentTarget);
    };

    const closeMenu = () => {
        setActiveFilter(null);
        setAnchorEl(null);
    };

    const statusLabel =
        selectedStatuses.length === 0
            ? "Status"
            : selectedStatuses.length === 1
                ? selectedStatuses[0]
                : `Status (${selectedStatuses.length})`;

    const agencyLabel =
        selectedPrimaryAgencyIds.length === 0
            ? "Gov’s Primary Agency"
            : selectedPrimaryAgencyIds.length === 1
                ? ministries.find(
                    (item) =>
                        item.id === selectedPrimaryAgencyIds[0],
                )?.label || "1 Agency"
                : `Agencies (${selectedPrimaryAgencyIds.length})`;

    const categoryLabel =
        selectedCategoryIds.length === 0
            ? "Category"
            : selectedCategoryIds.length === 1
                ? categories.find(
                    (item) =>
                        item.id === selectedCategoryIds[0],
                )?.label || "1 Category"
                : `Categories (${selectedCategoryIds.length})`;

    const meetingLabel = useMemo(() => {
        if (!meetingDate) {
            return "Meeting Date";
        }

        const value = parseMeetingMonth(meetingDate);

        return `${MONTH_OPTIONS[value.month]} ${value.year}`;
    }, [meetingDate]);

    const allStatusesSelected =
        selectedStatuses.length ===
        STATUS_OPTIONS.length;

    const someStatusesSelected =
        selectedStatuses.length > 0 &&
        !allStatusesSelected;

    const ministryIds = ministries.map(
        (item) => item.id,
    );

    const selectedValidMinistryCount =
        selectedPrimaryAgencyIds.filter((id) =>
            ministryIds.includes(id),
        ).length;

    const allMinistriesSelected =
        ministryIds.length > 0 &&
        selectedValidMinistryCount ===
        ministryIds.length;

    const someMinistriesSelected =
        selectedValidMinistryCount > 0 &&
        !allMinistriesSelected;

    const categoryIds = categories.map(
        (item) => item.id,
    );

    const selectedValidCategoryCount =
        selectedCategoryIds.filter((id) =>
            categoryIds.includes(id),
        ).length;

    const allCategoriesSelected =
        categoryIds.length > 0 &&
        selectedValidCategoryCount ===
        categoryIds.length;

    const someCategoriesSelected =
        selectedValidCategoryCount > 0 &&
        !allCategoriesSelected;

    return (
        <>
            <Box
                sx={{
                    display: "flex",
                    gap: 2,
                    mb: 2.5,
                    pb: 0.25,
                    overflowX: "auto",

                    "&::-webkit-scrollbar": {
                        height: 5,
                    },

                    "&::-webkit-scrollbar-thumb": {
                        bgcolor: theme.palette.divider,
                        borderRadius: 99,
                    },
                }}
            >
                <FilterButton
                    label={statusLabel}
                    open={activeFilter === "status"}
                    width={130}
                    onClick={(event) =>
                        openMenu("status", event)
                    }
                />

                <FilterButton
                    label={agencyLabel}
                    open={
                        activeFilter === "primaryAgency"
                    }
                    width={220}
                    onClick={(event) =>
                        openMenu(
                            "primaryAgency",
                            event,
                        )
                    }
                />

                <FilterButton
                    label={categoryLabel}
                    open={activeFilter === "category"}
                    width={260}
                    onClick={(event) =>
                        openMenu("category", event)
                    }
                />

                <FilterButton
                    label={meetingLabel}
                    open={activeFilter === "meetingDate"}
                    width={210}
                    onClick={(event) =>
                        openMenu("meetingDate", event)
                    }
                />

                <Button
                    variant="text"
                    onClick={() => {
                        onReset();
                        closeMenu();
                    }}
                    sx={{
                        flexShrink: 0,
                        textTransform: "none",
                        fontSize: 13,
                        fontWeight: 600,
                    }}
                >
                    Reset
                </Button>
            </Box>

            <Menu
                anchorEl={anchorEl}
                open={Boolean(anchorEl)}
                onClose={closeMenu}
                slotProps={{
                    paper: {
                        sx: {
                            mt: 0.75,
                            width:
                                activeFilter === "status"
                                    ? 210
                                    : activeFilter ===
                                        "meetingDate"
                                        ? 260
                                        : 280,
                            maxHeight: 330,
                            p: 0.5,
                            overflowY: "auto",
                            borderRadius: "8px",
                            border: `1px solid ${theme.palette.divider}`,
                            boxShadow:
                                "0 10px 30px rgba(15, 23, 42, 0.14)",
                        },
                    },
                }}
            >
                {loading &&
                    activeFilter !== "status" &&
                    activeFilter !== "meetingDate" ? (
                    <MenuItem disabled>
                        <CircularProgress
                            size={18}
                            sx={{ mr: 1 }}
                        />
                        Loading...
                    </MenuItem>
                ) : null}

                {lookupError &&
                    activeFilter !== "status" &&
                    activeFilter !== "meetingDate" ? (
                    <Box sx={{ p: 1 }}>
                        <Typography
                            sx={{
                                mb: 1,
                                color: theme.palette.error.main,
                                fontSize: 12,
                            }}
                        >
                            {lookupError}
                        </Typography>

                        <Button
                            size="small"
                            onClick={() => void loadLookups()}
                            sx={{
                                textTransform: "none",
                            }}
                        >
                            Retry
                        </Button>
                    </Box>
                ) : null}

                {activeFilter === "status" ? (
                    <>
                        <CheckOption
                            label="Select All"
                            checked={allStatusesSelected}
                            indeterminate={someStatusesSelected}
                            onClick={() =>
                                onSelectAllStatuses(
                                    STATUS_OPTIONS,
                                )
                            }
                        />

                        <Divider />

                        {STATUS_OPTIONS.map((status) => (
                            <CheckOption
                                key={status}
                                label={status}
                                checked={selectedStatuses.includes(
                                    status,
                                )}
                                onClick={() =>
                                    onToggleStatus(status)
                                }
                            />
                        ))}
                    </>
                ) : null}

                {!loading &&
                    !lookupError &&
                    activeFilter === "primaryAgency" ? (
                    <>
                        <CheckOption
                            label="Select All"
                            checked={allMinistriesSelected}
                            indeterminate={
                                someMinistriesSelected
                            }
                            onClick={() =>
                                onSelectAllPrimaryAgencies(
                                    ministryIds,
                                )
                            }
                        />

                        <Divider />

                        {ministries.length === 0 ? (
                            <MenuItem disabled>
                                No agencies found.
                            </MenuItem>
                        ) : (
                            ministries.map((item) => (
                                <CheckOption
                                    key={item.id}
                                    label={item.label}
                                    checked={selectedPrimaryAgencyIds.includes(
                                        item.id,
                                    )}
                                    onClick={() =>
                                        onTogglePrimaryAgency(
                                            item.id,
                                        )
                                    }
                                />
                            ))
                        )}
                    </>
                ) : null}

                {!loading &&
                    !lookupError &&
                    activeFilter === "category" ? (
                    <>
                        <CheckOption
                            label="Select All"
                            checked={allCategoriesSelected}
                            indeterminate={
                                someCategoriesSelected
                            }
                            onClick={() =>
                                onSelectAllCategories(
                                    categoryIds,
                                )
                            }
                        />

                        <Divider />

                        {categories.length === 0 ? (
                            <MenuItem disabled>
                                No categories found.
                            </MenuItem>
                        ) : (
                            categories.map((item) => (
                                <CheckOption
                                    key={item.id}
                                    label={item.label}
                                    checked={selectedCategoryIds.includes(
                                        item.id,
                                    )}
                                    onClick={() =>
                                        onToggleCategory(item.id)
                                    }
                                />
                            ))
                        )}
                    </>
                ) : null}

                {activeFilter === "meetingDate" ? (
                    <Box sx={{ p: 1.5 }}>
                        <Box
                            sx={{
                                display: "grid",
                                gridTemplateColumns:
                                    "1fr 1fr",
                                gap: 2,
                            }}
                        >
                            <Box sx={{ textAlign: "center" }}>
                                <Button
                                    aria-label="Previous month"
                                    onClick={() =>
                                        setDraftMonth(
                                            (current) =>
                                                current === 0
                                                    ? 11
                                                    : current - 1,
                                        )
                                    }
                                >
                                    <KeyboardArrowUpRoundedIcon />
                                </Button>

                                <Typography
                                    sx={{
                                        fontSize: 18,
                                        fontWeight: 600,
                                    }}
                                >
                                    {MONTH_OPTIONS[draftMonth]}
                                </Typography>

                                <Button
                                    aria-label="Next month"
                                    onClick={() =>
                                        setDraftMonth(
                                            (current) =>
                                                current === 11
                                                    ? 0
                                                    : current + 1,
                                        )
                                    }
                                >
                                    <KeyboardArrowDownRoundedIcon />
                                </Button>
                            </Box>

                            <Box sx={{ textAlign: "center" }}>
                                <Button
                                    aria-label="Next year"
                                    onClick={() =>
                                        setDraftYear(
                                            (current) =>
                                                current + 1,
                                        )
                                    }
                                >
                                    <KeyboardArrowUpRoundedIcon />
                                </Button>

                                <Typography
                                    sx={{
                                        fontSize: 18,
                                        fontWeight: 600,
                                    }}
                                >
                                    {draftYear}
                                </Typography>

                                <Button
                                    aria-label="Previous year"
                                    onClick={() =>
                                        setDraftYear(
                                            (current) =>
                                                current - 1,
                                        )
                                    }
                                >
                                    <KeyboardArrowDownRoundedIcon />
                                </Button>
                            </Box>
                        </Box>

                        <Box
                            sx={{
                                mt: 1,
                                display: "flex",
                                justifyContent: "flex-end",
                                gap: 1,
                            }}
                        >
                            {meetingDate ? (
                                <Button
                                    onClick={() => {
                                        onMeetingDateChange("");
                                        closeMenu();
                                    }}
                                    sx={{
                                        textTransform: "none",
                                    }}
                                >
                                    Clear
                                </Button>
                            ) : null}

                            <Button
                                variant="contained"
                                onClick={() => {
                                    onMeetingDateChange(
                                        formatMeetingMonth(
                                            draftMonth,
                                            draftYear,
                                        ),
                                    );

                                    closeMenu();
                                }}
                                sx={{
                                    textTransform: "none",
                                }}
                            >
                                Show
                            </Button>
                        </Box>
                    </Box>
                ) : null}
            </Menu>
        </>
    );
}

export default MinistryRgcDecisionFilters;