"use client";

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

import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import { alpha, useTheme } from "@mui/material/styles";

import {
  cdcGpsfMeetingCalendarI18n,
  type CdcGpsfMeetingCalendarUiLang,
} from "@/features/cdc-gpsf/meeting-calendar/cdc-gpsf-meeting-calendar-i18n";
import {
  getChangedMeetingDate,
  getMeetingById,
  getMeetingCalendarEvents,
  MEETING_CHANGED_EVENT,
  MEETING_CHANGED_STORAGE_KEY,
  type MeetingCalendarEvent,
} from "@/features/cdc-gpsf/meeting-calendar/service/cdc-gpsf-meeting-calendar-service";
import {
  MeetingDetailDialog,
  type DetailMeeting,
} from "@/features/ministry/meeting-calendar/components/meeting-detail-dialog";
import { MinistryMeetingCalendarGrid } from "@/features/ministry/meeting-calendar/components/ministry-meeting-calendar-grid";
import type {
  MeetingCalendarRow,
  MeetingCalendarStatus,
} from "@/features/ministry/meeting-calendar/meeting-calendar-data";

type CalendarMonth = {
  year: number;
  monthIndex: number;
};

function getCalendarMonth(dateKey?: string): CalendarMonth {
  const date = dateKey ? new Date(`${dateKey}T00:00:00`) : new Date();

  if (Number.isNaN(date.getTime())) {
    return {
      year: new Date().getFullYear(),
      monthIndex: new Date().getMonth(),
    };
  }

  return {
    year: date.getFullYear(),
    monthIndex: date.getMonth(),
  };
}

function getMeetingStatus(status: MeetingCalendarEvent["status"]): MeetingCalendarStatus {
  if (status === "Completed") return "Completed";
  if (status === "Submitted") return "Submitted";

  // The Ministry calendar has no Under Review meeting status. It uses the
  // Scheduled layout for this legacy CDC-GPSF event value.
  return "Scheduled";
}

function mapCalendarEventToRow(event: MeetingCalendarEvent): MeetingCalendarRow {
  const year = Number(event.date.slice(0, 4));

  return {
    id: Number(event.id),
    meetingSummaryId: null,
    title: event.title,
    workingGroup: event.governmentAgency,
    description: event.description,
    issueCount: event.issues.length,
    meetingRequest: event.documentName,
    meetingDate: event.meetingUpdate?.meetingDate || event.date,
    dateKey: event.date,
    timeRange: event.meetingUpdate?.meetingTime || event.time,
    participantCount: event.participants,
    status: getMeetingStatus(event.status),
    year: Number.isNaN(year) ? 0 : year,
  };
}

type CdcGpsfMeetingCalendarProps = {
  language?: CdcGpsfMeetingCalendarUiLang;
};

export function CdcGpsfMeetingCalendar({
  language = "km",
}: CdcGpsfMeetingCalendarProps) {
  const theme = useTheme();
  const t = cdcGpsfMeetingCalendarI18n(language);

  const [calendarMonth, setCalendarMonth] = useState<CalendarMonth>(() =>
    getCalendarMonth(),
  );
  const [detailMeeting, setDetailMeeting] = useState<DetailMeeting | null>(
    null,
  );
  const [detailDialogOpen, setDetailDialogOpen] = useState(false);
  const [meetingEvents, setMeetingEvents] = useState<MeetingCalendarEvent[]>([]);
  const [loading, setLoading] = useState(true);
  const [hasLoaded, setHasLoaded] = useState(false);
  const [error, setError] = useState("");

  const loadMeetings = useCallback(
    async (
      signal?: AbortSignal,
      options: { background?: boolean } = {},
    ) => {
      const { background = false } = options;

      try {
        if (!background) {
          setLoading(true);
        }

        setError("");
        const events = await getMeetingCalendarEvents(signal);
        if (signal?.aborted) return;

        setMeetingEvents(events);
        setHasLoaded(true);
      } catch (requestError) {
        if (signal?.aborted) return;

        setError(
          requestError instanceof Error ? requestError.message : "Unable to load meetings.",
        );
      } finally {
        if (!signal?.aborted && !background) {
          setLoading(false);
        }
      }
    },
    [],
  );

  useEffect(() => {
    const controller = new AbortController();
    // eslint-disable-next-line react-hooks/set-state-in-effect -- initial data fetch with abort handling
    void loadMeetings(controller.signal);

    return () => controller.abort();
  }, [loadMeetings]);

  useEffect(() => {
    const refresh = () => {
      void loadMeetings(undefined, { background: true });
    };

    const moveCalendarToMeetingDate = (dateKey?: string) => {
      if (dateKey) {
        setCalendarMonth(getCalendarMonth(dateKey));
      }

      refresh();
    };

    const handleMeetingChanged = (event: Event) => {
      const customEvent = event as CustomEvent<{ meetingDate?: string }>;
      moveCalendarToMeetingDate(customEvent.detail?.meetingDate);
    };

    const handleStorage = (event: StorageEvent) => {
      if (event.key !== MEETING_CHANGED_STORAGE_KEY) return;

      moveCalendarToMeetingDate(getChangedMeetingDate(event.newValue));
    };

    window.addEventListener(MEETING_CHANGED_EVENT, handleMeetingChanged);
    window.addEventListener("storage", handleStorage);

    return () => {
      window.removeEventListener(MEETING_CHANGED_EVENT, handleMeetingChanged);
      window.removeEventListener("storage", handleStorage);
    };
  }, [loadMeetings]);

  const rows = useMemo(
    () => meetingEvents.map(mapCalendarEventToRow),
    [meetingEvents],
  );

  const handleEventClick = async (row: MeetingCalendarRow) => {
    try {
      setError("");
      const meeting = (await getMeetingById(row.id)) as DetailMeeting;
      setDetailMeeting(meeting);
      setDetailDialogOpen(true);
    } catch (requestError) {
      setError(requestError instanceof Error ? requestError.message : t.error);
    }
  };

  return (
    <>
      {((loading && !hasLoaded) || error) && (
        <Box sx={{ mb: 1, px: 1 }}>
          <Typography
            sx={{
              color: error
                ? "#f04438"
                : theme.palette.mode === "dark"
                  ? alpha("#ffffff", 0.68)
                  : "#667085",
              fontSize: 13,
              fontWeight: 500,
            }}
          >
            {error || t.loading}
          </Typography>
        </Box>
      )}

      <MinistryMeetingCalendarGrid
        key={`${calendarMonth.year}-${calendarMonth.monthIndex}`}
        rows={rows}
        initialMonth={calendarMonth}
        onView={(row) => void handleEventClick(row)}
      />

      <MeetingDetailDialog
        open={detailDialogOpen}
        meeting={detailMeeting}
        onClose={() => {
          setDetailDialogOpen(false);
          setDetailMeeting(null);
        }}
      />
    </>
  );
}
