"use client";

// Top-level screen for /cdc-gpsf/progress-reports.
// It holds the filter state, picks the current language, and composes the
// page: header -> filter row -> table.

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

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

import { useAppLanguage } from "@/components/providers/app-language-provider";
import { ToastNotification } from "@/components/ui/toast-notification";

import {
  useProgressReportMutations,
  useProgressReports,
} from "../hook/use-progress-reports";
import { getInitialCalendarMonth } from "../progress-report-calendar-data";
import {
  defaultProgressReportFilters,
  filterProgressReportRows,
  type ProgressReportFiltersValue,
  type ProgressReportView,
} from "../progress-report-data";
import {
  normalizeProgressReportLanguage,
  progressReportText,
  translateProgressReportValue,
} from "../progress-report-i18n";
import type { ProgressReportMeetingSlot } from "../service/progress-report-service";
import { ProgressReportCalendar } from "./calendar/progress-report-calendar";
import type {
  CreateMeetingFormValues,
  CreateMeetingSubmitMode,
} from "./create-meeting-dialog/create-meeting-dialog-types";
import { CreateProgressReportDialog } from "./create-progress-report-dialog/create-progress-report-dialog";
import type {
  CreateProgressReportFormValues,
  CreateProgressReportSubmitMode,
} from "./create-progress-report-dialog/create-progress-report-dialog-types";
import { ProgressReportFilters } from "./progress-report-filters";
import { ProgressReportHeader } from "./progress-report-header";
import type { SetDeadlineSlot } from "./set-deadline-dialog/set-deadline-dialog";
import type { ProgressReportRowActions } from "./table/progress-report-actions-menu";
import { ProgressReportTable } from "./table/progress-report-table";

function getDateKey(value: string) {
  return value.match(/^\d{4}-\d{2}-\d{2}/)?.[0] ?? "";
}

export function ProgressReportScreen() {
  const theme = useTheme();
  const isDark = theme.palette.mode === "dark";

  // Current UI language ("en" or "kh") and the matching text labels.
  const { language } = useAppLanguage();
  const pageLanguage = normalizeProgressReportLanguage(language);
  const labels = progressReportText[pageLanguage];

  const [filters, setFilters] = useState<ProgressReportFiltersValue>({
    ...defaultProgressReportFilters,
  });
  const {
    rows: fetchedRows,
    calendarEvents,
    isLoading,
    error,
  } = useProgressReports();
  const {
    createReport,
    updateReport,
    createMeeting,
    sendMeeting,
    sendReport,
    createDeadline,
    updateDeadline,
    sendDeadline,
    uploadDraftSemester,
  } = useProgressReportMutations();
  const [newReportDialogOpen, setNewReportDialogOpen] = useState(false);
  const [successMessage, setSuccessMessage] = useState("");

  const reportRows = fetchedRows;

  // Which view is showing: the reports table or the calendar.
  const [view, setView] = useState<ProgressReportView>("reports");

  // Rows shown in the table = API rows narrowed by the selected filters.
  const rows = useMemo(
    () => filterProgressReportRows(reportRows, filters),
    [filters, reportRows],
  );

  // Translates values inside table cells (e.g. "Sent" -> Khmer) when needed.
  const translateValue = useCallback(
    (value: string) => translateProgressReportValue(value, pageLanguage),
    [pageLanguage],
  );

  const handleCreateReport = useCallback(
    async (
      values: CreateProgressReportFormValues,
      mode: CreateProgressReportSubmitMode,
    ) => {
      if (!values.attachment) {
        throw new Error(labels.createDialog.required);
      }

      // The API always creates a draft, so sending is a second call.
      const created = await createReport({
        title: values.title.trim(),
        description: values.description.trim(),
        year: Number(values.year),
        semester: values.semester === "S2" ? "S2" : "S1",
        firstDeadline: values.deadline,
        attachment: values.attachment,
      });

      if (mode === "sent") {
        await sendReport({ progressReportId: created.data.id });
      }

      setSuccessMessage(labels.successMessages.reportCreated);
    },
    [
      createReport,
      sendReport,
      labels.createDialog.required,
      labels.successMessages,
    ],
  );

  const handleCreateMeeting = useCallback(
    async (
      progressReportId: number,
      slot: ProgressReportMeetingSlot,
      values: CreateMeetingFormValues,
      mode: CreateMeetingSubmitMode,
    ) => {
      if (!values.document) {
        throw new Error(labels.createMeetingDialog.required);
      }

      // The API always creates a draft, so sending is a second call.
      const created = await createMeeting({
        progressReportId,
        slot,
        title: values.name.trim(),
        description: values.description,
        meetingDate: values.date,
        startTime: values.startTime,
        endTime: values.endTime,
        location: values.location.trim(),
        document: values.document,
      });

      if (mode === "sent") {
        await sendMeeting({ meetingId: created.data.id });
      }

      setSuccessMessage(labels.successMessages.meetingCreated);
    },
    [
      createMeeting,
      sendMeeting,
      labels.createMeetingDialog.required,
      labels.successMessages,
    ],
  );

  const handleEditReport = useCallback(
    async (
      progressReportId: number,
      currentDeadline: string,
      firstDeadlineId: number | null,
      values: CreateProgressReportFormValues,
      mode: CreateProgressReportSubmitMode,
    ) => {
      const deadlineChanged =
        values.deadline !== getDateKey(currentDeadline);

      await updateReport({
        progressReportId,
        title: values.title.trim(),
        description: values.description.trim(),
        year: Number(values.year),
        semester: values.semester === "S2" ? "S2" : "S1",
        ...(values.attachment ? { attachment: values.attachment } : {}),
      });

      // The FIRST deadline lives on its own resource now.
      if (deadlineChanged && firstDeadlineId) {
        await updateDeadline({
          deadlineId: firstDeadlineId,
          deadline: values.deadline,
        });
      }

      if (mode === "sent") {
        await sendReport({ progressReportId });
      }

      setSuccessMessage(labels.successMessages.reportUpdated);
    },
    [
      labels.successMessages.reportUpdated,
      sendReport,
      updateDeadline,
      updateReport,
    ],
  );

  // The modal fills one slot at a time, so this saves a single deadline.
  const handleSetDeadline = useCallback(
    async (
      progressReportId: number,
      slot: SetDeadlineSlot,
      deadlineId: number | null,
      deadline: string,
      shouldSend: boolean,
    ) => {
      let savedDeadlineId = deadlineId;

      if (savedDeadlineId) {
        await updateDeadline({ deadlineId: savedDeadlineId, deadline });
      } else {
        const created = await createDeadline({
          progressReportId,
          slot,
          deadline,
        });
        savedDeadlineId = created.data.id;
      }

      if (shouldSend && savedDeadlineId) {
        await sendDeadline({ deadlineId: savedDeadlineId });
      }
      setSuccessMessage(
        shouldSend
          ? labels.successMessages.deadlinesSent
          : labels.successMessages.deadlinesSaved,
      );
    },
    [createDeadline, labels.successMessages, sendDeadline, updateDeadline],
  );

  const handleUploadDraftSemester = useCallback(
    async (progressReportId: number, file: File) => {
      await uploadDraftSemester({ progressReportId, file });
      setSuccessMessage(labels.successMessages.draftSemesterUploaded);
    },
    [labels.successMessages, uploadDraftSemester],
  );

  const rowActions = useMemo<ProgressReportRowActions>(
    () => ({
      editReport: handleEditReport,
      createMeeting: handleCreateMeeting,
      setDeadline: handleSetDeadline,
      uploadDraftSemester: handleUploadDraftSemester,
    }),
    [
      handleCreateMeeting,
      handleEditReport,
      handleSetDeadline,
      handleUploadDraftSemester,
    ],
  );

  return (
    <Box
      sx={{
        // Page-wide color variables so every child styles itself
        // correctly in both light and dark mode.
        "--mr-text": isDark ? "#E5E7EB" : "#181D27",
        "--mr-muted": isDark ? "#CBD5E1" : "#717680",
        "--mr-border": isDark ? "#243244" : "#F5F5F5",
        "--mr-header": isDark ? "#29415F" : "#DDEDFB",
        "--mr-blue": isDark ? "#60A5FA" : "#1A64A8",

        minHeight: "calc(100dvh - 64px)",
        width: "100%",
        minWidth: 0,
        display: "flex",
        flexDirection: "column",
        px: { xs: 2, md: 2.5 },
        py: { xs: 2.5, md: 2 },
        color: "var(--mr-text)",
        bgcolor: "transparent",
      }}
    >
      <Box
        sx={{
          flex: 1,
          minHeight: 0,
          display: "flex",
          flexDirection: "column",
          gap: 2,
        }}
      >
        <ProgressReportHeader
          labels={labels}
          view={view}
          onNewReport={() => setNewReportDialogOpen(true)}
        />

        <ProgressReportFilters
          rows={reportRows}
          filters={filters}
          onFiltersChange={setFilters}
          labels={labels}
          language={pageLanguage}
          view={view}
          onViewChange={setView}
        />

        {view === "reports" ? (
          <Box
            sx={{
              flex: 1,
              minHeight: 0,
              display: "flex",
              flexDirection: "column",
            }}
          >
            <ProgressReportTable
              rows={rows}
              columnLabels={labels.columns}
              actionsMenuLabels={labels.actionsMenu}
              editReportLabels={labels.createDialog}
              uploadDraftSemesterLabels={labels.uploadDraftSemesterDialog}
              createMeetingLabels={labels.createMeetingDialog}
              setDeadlineLabels={labels.setDeadlineDialog}
              emptyStateLabels={labels.emptyState}
              translateValue={translateValue}
              loading={isLoading}
              error={error}
              rowActions={rowActions}
            />
          </Box>
        ) : isLoading ? (
          <Box
            sx={{
              minHeight: 320,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
            }}
          >
            <CircularProgress size={30} />
          </Box>
        ) : error ? (
          <Box
            sx={{
              minHeight: 240,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              px: 2,
            }}
          >
            <Typography sx={{ color: "error.main", textAlign: "center" }}>
              {error}
            </Typography>
          </Box>
        ) : (
          <ProgressReportCalendar
            events={calendarEvents}
            initialMonth={getInitialCalendarMonth(calendarEvents)}
            dialogLabels={labels.eventDialog}
          />
        )}
      </Box>

      <CreateProgressReportDialog
        open={newReportDialogOpen}
        labels={labels.createDialog}
        onClose={() => setNewReportDialogOpen(false)}
        onSubmit={handleCreateReport}
      />

      <ToastNotification
        open={Boolean(successMessage)}
        message={successMessage}
        onClose={() => setSuccessMessage("")}
      />
    </Box>
  );
}
