"use client";

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

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

import { useAppLanguage } from "@/components/providers/app-language-provider";
import type { ListGridViewMode } from "@/components/ui/list-grid-view-toggle";
import { ToastNotification } from "@/components/ui/toast-notification";

import {
  useProgressReport,
  useProgressReportMinistries,
  useProgressReportMutations,
} from "../../hook/use-progress-reports";
import {
  getMinistryRowAttachmentName,
  mapApiProgressReportMinistryToRow,
  mapApiProgressReportToDetail,
} from "../../progress-report-detail-data";
import {
  normalizeProgressReportLanguage,
  progressReportText,
  translateProgressReportValue,
} from "../../progress-report-i18n";
import {
  mapApiProgressReportToScheduleRows,
  type ProgressReportScheduleRow,
} from "../../progress-report-schedule-data";
import {
  getProgressReportMeeting,
  type ApiProgressReportMeetingDetail,
} from "../../service/progress-report-service";
import { CreateMeetingDialog } from "../create-meeting-dialog/create-meeting-dialog";
import type {
  CreateMeetingFormValues,
  CreateMeetingSubmitMode,
  MeetingFormInitialValues,
} from "../create-meeting-dialog/create-meeting-dialog-types";
import { SetDeadlineDialog } from "../set-deadline-dialog/set-deadline-dialog";
import {
  ProgressReportDetailFilters,
  type ProgressReportDetailFilterValue,
} from "./progress-report-detail-filters";
import { ProgressReportDetailHeader } from "./progress-report-detail-header";
import { ProgressReportDetailInformation } from "./progress-report-detail-information";
import { ProgressReportDetailTable } from "./progress-report-detail-table";
import { ProgressReportMeetingsDeadlinesTable } from "./progress-report-meetings-deadlines-table";

const emptyFilters: ProgressReportDetailFilterValue = {
  ministry: "",
  attachment: "",
};

function getEditorValue(value: unknown) {
  if (typeof value === "string") return value;
  if (value === null || value === undefined) return "";
  return JSON.stringify(value);
}

export function ProgressReportDetailScreen({ id }: { id: string }) {
  const theme = useTheme();
  const { language } = useAppLanguage();
  const pageLanguage = normalizeProgressReportLanguage(language);
  const labels = progressReportText[pageLanguage];
  const {
    report: apiReport,
    isValidId,
    isLoading,
    error,
  } = useProgressReport(id);
  const {
    assignments,
    isLoading: ministriesLoading,
    error: ministriesError,
  } = useProgressReportMinistries(id);
  const {
    createMeeting,
    updateMeeting,
    sendMeeting,
    sendReport,
    createDeadline,
    updateDeadline,
    sendDeadline,
  } = useProgressReportMutations();
  const report = useMemo(
    () => (apiReport ? mapApiProgressReportToDetail(apiReport) : null),
    [apiReport],
  );
  const [filters, setFilters] = useState<ProgressReportDetailFilterValue>({
    ...emptyFilters,
  });
  const [viewMode, setViewMode] = useState<ListGridViewMode>("grid");
  const [activeScheduleRow, setActiveScheduleRow] =
    useState<ProgressReportScheduleRow | null>(null);
  const [meetingDetail, setMeetingDetail] =
    useState<ApiProgressReportMeetingDetail | null>(null);
  const [loadingActionRowId, setLoadingActionRowId] = useState<string | null>(
    null,
  );
  const [scheduleActionError, setScheduleActionError] = useState("");
  const [successMessage, setSuccessMessage] = useState("");

  const ministryRows = useMemo(
    () => assignments.map(mapApiProgressReportMinistryToRow),
    [assignments],
  );

  const filteredRows = useMemo(
    () =>
      ministryRows.filter((row) => {
        const matchesMinistry =
          !filters.ministry || row.name === filters.ministry;
        const matchesAttachment =
          !filters.attachment ||
          getMinistryRowAttachmentName(row) === filters.attachment;

        return matchesMinistry && matchesAttachment;
      }),
    [filters, ministryRows],
  );

  const scheduleRows = useMemo(
    () => (apiReport ? mapApiProgressReportToScheduleRows(apiReport) : []),
    [apiReport],
  );

  const meetingInitialValues = useMemo<MeetingFormInitialValues | undefined>(
    () =>
      meetingDetail
        ? {
            name: meetingDetail.title,
            description: getEditorValue(meetingDetail.description),
            date: meetingDetail.meetingDate,
            startTime: meetingDetail.startTime.slice(0, 5),
            endTime: meetingDetail.endTime.slice(0, 5),
            location: meetingDetail.location,
          }
        : undefined,
    [meetingDetail],
  );

  const handleScheduleAction = useCallback(
    async (row: ProgressReportScheduleRow) => {
      if (row.action === "blocked" || row.action === "locked") return;

      setScheduleActionError("");

      if (row.type === "meeting" && row.action === "edit") {
        if (!row.resourceId) return;

        setLoadingActionRowId(row.id);

        try {
          const detail = await getProgressReportMeeting(row.resourceId);
          setMeetingDetail(detail);
          setActiveScheduleRow(row);
        } catch (requestError) {
          setScheduleActionError(
            requestError instanceof Error
              ? requestError.message
              : labels.detail.scheduleActions.loadMeetingError,
          );
        } finally {
          setLoadingActionRowId(null);
        }

        return;
      }

      setMeetingDetail(null);
      setActiveScheduleRow(row);
    },
    [labels.detail.scheduleActions.loadMeetingError],
  );

  const closeScheduleDialog = useCallback(() => {
    setActiveScheduleRow(null);
    setMeetingDetail(null);
  }, []);

  async function handleMeetingSubmit(
    values: CreateMeetingFormValues,
    mode: CreateMeetingSubmitMode,
  ) {
    if (!activeScheduleRow || activeScheduleRow.type !== "meeting") return;

    let meetingId = activeScheduleRow.resourceId;

    if (meetingId) {
      await updateMeeting({
        meetingId,
        title: values.name.trim(),
        description: values.description,
        meetingDate: values.date,
        startTime: values.startTime,
        endTime: values.endTime,
        location: values.location.trim(),
        ...(values.document ? { document: values.document } : {}),
      });
    } else {
      if (!values.document) {
        throw new Error(labels.createMeetingDialog.required);
      }

      const created = await createMeeting({
        progressReportId: Number(id),
        slot: activeScheduleRow.slot === "SECOND" ? "SECOND" : "FIRST",
        title: values.name.trim(),
        description: values.description,
        meetingDate: values.date,
        startTime: values.startTime,
        endTime: values.endTime,
        location: values.location.trim(),
        document: values.document,
      });
      meetingId = created.data.id;
    }

    if (mode === "sent" && meetingId) {
      await sendMeeting({ meetingId });
    }

    setSuccessMessage(
      mode === "sent"
        ? labels.detail.scheduleActions.meetingSent
        : labels.detail.scheduleActions.meetingSaved,
    );
  }

  async function handleDeadlineSubmit(
    deadline: string,
    shouldSend: boolean,
  ) {
    if (!activeScheduleRow || activeScheduleRow.type !== "deadline") return;

    let deadlineId = activeScheduleRow.resourceId;

    if (deadlineId) {
      await updateDeadline({ deadlineId, deadline });
    } else {
      if (activeScheduleRow.slot === "FIRST") {
        throw new Error(labels.detail.scheduleActions.blocked);
      }

      const created = await createDeadline({
        progressReportId: Number(id),
        slot: activeScheduleRow.slot,
        deadline,
      });
      deadlineId = created.data.id;
    }

    if (shouldSend) {
      if (activeScheduleRow.slot === "FIRST") {
        await sendReport({ progressReportId: Number(id) });
      } else if (deadlineId) {
        await sendDeadline({ deadlineId });
      }
    }

    setSuccessMessage(
      shouldSend
        ? labels.detail.scheduleActions.deadlineSent
        : labels.detail.scheduleActions.deadlineSaved,
    );
  }

  const translatedTitle = report
    ? translateProgressReportValue(report.title, pageLanguage)
    : labels.breadcrumbCurrent;
  const pageError = !isValidId
    ? labels.detail.invalidReportId
    : error || (!isLoading && !report ? labels.detail.loadError : null);

  return (
    <Box
      sx={{
        width: "100%",
        minWidth: 0,
        minHeight: "100%",
        px: { xs: 2, md: 2.5 },
        pt: { xs: 2, md: 0 },
        pb: 3,
        color: theme.palette.text.primary,
        bgcolor: theme.palette.background.default,
      }}
    >
      <Box sx={{ display: "flex", flexDirection: "column", gap: 3 }}>
        {isLoading ? (
          <Box
            sx={{
              minHeight: 320,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
            }}
          >
            <CircularProgress size={32} />
          </Box>
        ) : pageError || !report ? (
          <>
            <ProgressReportDetailHeader
              title={translatedTitle}
              labels={labels}
            />
            <Alert severity="error">
              {pageError || labels.detail.loadError}
            </Alert>
          </>
        ) : (
          <>
            <ProgressReportDetailHeader
              title={translatedTitle}
              labels={labels}
            />

            <ProgressReportDetailInformation
              report={report}
              labels={labels.detail}
            />

            <ProgressReportDetailFilters
              rows={ministryRows}
              value={filters}
              labels={labels.detail}
              onChange={setFilters}
              viewMode={viewMode}
              onViewModeChange={setViewMode}
            />

            {viewMode === "list" ? (
              <>
                {scheduleActionError ? (
                  <Alert severity="error">{scheduleActionError}</Alert>
                ) : null}
                <ProgressReportMeetingsDeadlinesTable
                  rows={scheduleRows}
                  labels={labels.detail}
                  loadingActionRowId={loadingActionRowId}
                  onAction={handleScheduleAction}
                />
              </>
            ) : (
              <ProgressReportDetailTable
                rows={filteredRows}
                labels={labels.detail}
                reportId={id}
                loading={ministriesLoading}
                error={ministriesError}
              />
            )}
          </>
        )}
      </Box>

      {activeScheduleRow?.type === "meeting" ? (
        <CreateMeetingDialog
          key={`${activeScheduleRow.id}-${activeScheduleRow.resourceId ?? "new"}`}
          open
          labels={labels.createMeetingDialog}
          title={
            activeScheduleRow.resourceId
              ? labels.detail.scheduleActions.editMeetingTitle
              : labels.createMeetingDialog.title
          }
          defaultName={
            apiReport ? `${apiReport.title} | ${apiReport.year}` : ""
          }
          initialValues={meetingInitialValues}
          existingDocument={meetingDetail?.documentReference}
          onClose={closeScheduleDialog}
          onSubmit={handleMeetingSubmit}
        />
      ) : null}

      {activeScheduleRow?.type === "deadline" ? (
        <SetDeadlineDialog
          key={`${activeScheduleRow.id}-${activeScheduleRow.date}`}
          open
          labels={labels.setDeadlineDialog}
          title={
            activeScheduleRow.resourceId
              ? labels.detail.scheduleActions.editDeadlineTitle
              : labels.setDeadlineDialog.title
          }
          slot={activeScheduleRow.slot}
          initialDate={
            activeScheduleRow.date === "-" ? "" : activeScheduleRow.date
          }
          onClose={closeScheduleDialog}
          onSave={(deadline) => handleDeadlineSubmit(deadline, false)}
          onSend={(deadline) => handleDeadlineSubmit(deadline, true)}
        />
      ) : null}

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

export default ProgressReportDetailScreen;
