"use client";

import { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";

import AddBoxOutlinedIcon from "@mui/icons-material/AddBoxOutlined";
import CalendarMonthOutlinedIcon from "@mui/icons-material/CalendarMonthOutlined";
import FormatListBulletedRoundedIcon from "@mui/icons-material/FormatListBulletedRounded";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Snackbar from "@mui/material/Snackbar";
import Typography from "@mui/material/Typography";
import { useTheme } from "@mui/material/styles";

import { ToastNotification } from "@/components/ui/toast-notification";
import { useMeetingRequestI18n } from "@/features/ministry/meeting-request/use-meeting-request-i18n";
import {
  createMeetingSavePayload,
  mapApiMeetingToCreateForm,
  type MeetingCreateForm,
} from "../meeting-create-form";
import { MeetingCreateDialog } from "./create-meeting/meeting-create-dialog";
import { useCurrentUser } from "@/features/auth/hook/use-current-user";
import type {
  MeetingRequestGovernmentAgency,
  MeetingRequestIssue,
} from "@/features/ministry/meeting-request/meeting-request-data";
import {
  getDisplayFileName,
  type UploadedFileMetadata,
} from "@/lib/document-file";

import {
  createMeeting,
  getMeetingById,
  getMeetingCalendarRows,
  updateMeeting,
} from "../meeting-calendar-service";
import {
  defaultMeetingCalendarFilters,
  filterMeetingCalendarRows,
  getCalendarMonthFromRows,
  getMeetingCalendarYears,
  getMeetingSummaryAction,
  mapMeetingCalendarIssues,
  type MeetingCalendarFilters,
  type MeetingCalendarRow,
  type MeetingCalendarStatus,
} from "../meeting-calendar-data";
import { MinistryMeetingCalendarFilters } from "./ministry-meeting-calendar-filters";
import { MinistryMeetingCalendarGrid } from "./ministry-meeting-calendar-grid";
import { MinistryMeetingCalendarTable } from "./table/ministry-meeting-calendar-table";
import {
  MeetingDetailDialog,
  type DetailMeeting,
} from "./meeting-detail-dialog";

type FilterKey = keyof MeetingCalendarFilters;
type MeetingCalendarView = "table" | "calendar";

function getDocumentPath(value?: UploadedFileMetadata | string | null) {
  if (!value) return null;
  return typeof value === "string" ? value : value.path;
}

type EditMeetingContext = {
  id: number;
  initialForm: Partial<MeetingCreateForm>;
  meetingRequestId?: number;
  issues?: MeetingRequestIssue[];
  governmentAgencies?: MeetingRequestGovernmentAgency[];
  meetingRequest?: {
    id: number;
    requestedBy: string;
    requestedDate: string;
    documentName: string;
    privateSectorWG?: string;
    submittedBy?: string;
  };
};

function getMeetingStatusToKeep(status?: string): MeetingCalendarStatus {
  switch (status?.trim().toUpperCase()) {
    case "SCHEDULED":
      return "Scheduled";
    case "SUBMITTED":
      return "Submitted";
    case "COMPLETED":
      return "Completed";
    default:
      return "Draft";
  }
}

function getApiOrigin() {
  const raw =
    process.env.NEXT_PUBLIC_API_URL ??
    process.env.NEXT_PUBLIC_API_BASE_URL ??
    "http://localhost:3001/api/v1";

  return raw.replace(/\/api\/v\d+\/?$/, "").replace(/\/+$/, "");
}

function getMediaUrl(path?: string | null) {
  if (!path) return "";
  if (/^https?:\/\//i.test(path)) return path;
  return `${getApiOrigin()}${path.startsWith("/") ? path : `/${path}`}`;
}

export default function MinistryMeetingCalendarScreen() {
  const router = useRouter();
  const theme = useTheme();
  const isDark = theme.palette.mode === "dark";
  const { t } = useMeetingRequestI18n();
  const calendarLabels = t.meetingCalendar;

  const [filters, setFilters] = useState<MeetingCalendarFilters>(
    defaultMeetingCalendarFilters,
  );
  const { user: currentUser } = useCurrentUser();
  const [activeView, setActiveView] = useState<MeetingCalendarView>("table");
  const [rows, setRows] = useState<MeetingCalendarRow[]>([]);
  const [loading, setLoading] = useState(true);
  const [createDialogOpen, setCreateDialogOpen] = useState(false);
  const [editMeeting, setEditMeeting] = useState<EditMeetingContext | null>(
    null,
  );
  const [detailMeeting, setDetailMeeting] = useState<DetailMeeting | null>(
    null,
  );
  const [detailDialogOpen, setDetailDialogOpen] = useState(false);
  const [notice, setNotice] = useState<string | null>(null);
  const [toastMessage, setToastMessage] = useState<string | null>(null);
  const [scheduleSuccessOpen, setScheduleSuccessOpen] = useState(false);

  useEffect(() => {
    let isActive = true;

    async function loadMeetings() {
      try {
        const apiRows = await getMeetingCalendarRows();

        if (!isActive) return;

        setRows(apiRows);
      } catch {
        if (!isActive) return;

        setRows([]);
        setNotice(calendarLabels.loadMeetingsError);
      } finally {
        if (isActive) {
          setLoading(false);
        }
      }
    }

    loadMeetings();

    return () => {
      isActive = false;
    };
  }, [calendarLabels.loadMeetingsError]);

  const filteredRows = useMemo(
    () => filterMeetingCalendarRows(rows, filters),
    [rows, filters],
  );

  const yearOptions = useMemo(() => getMeetingCalendarYears(rows), [rows]);

  const calendarInitialMonth = useMemo(() => {
    const month = getCalendarMonthFromRows(filteredRows);

    if (filters.year.length === 1) {
      return {
        ...month,
        year: Number(filters.year[0]),
      };
    }

    return month;
  }, [filteredRows, filters.year]);

  const handleFilterChange = (key: FilterKey, value: string[]) => {
    setFilters((current) => ({
      ...current,
      [key]: value,
    }));
  };

  const refreshMeetings = async () => {
    const apiRows = await getMeetingCalendarRows();
    setRows(apiRows);

    return apiRows;
  };

  // After the Ministry adds an issue, reload the meeting that is open so its
  // issue table shows the new row.
  const handleIssueAdded = async () => {
    const apiRows = await refreshMeetings();

    if (!editMeeting) return;

    const row = apiRows.find((item) => item.id === editMeeting.id);
    if (row) await handleEditMeeting(row);
  };

  const getCurrentUserId = () => {
    if (!currentUser?.id) {
      throw new Error(t.detail.waitForProfile);
    }

    return currentUser.id;
  };

  const handleSaveDraftMeeting = async (form: MeetingCreateForm) => {
    await createMeeting(
      createMeetingSavePayload(form, {
        status: "Draft",
        userId: getCurrentUserId(),
        meetingRequestId: form.meetingRequestId,
      }),
    );
    await refreshMeetings();
    setToastMessage(t.detail.meetingDraftSuccess);
  };

  const handleScheduleMeeting = async (form: MeetingCreateForm) => {
    await createMeeting(
      createMeetingSavePayload(form, {
        status: "Scheduled",
        sendInvites: true,
        userId: getCurrentUserId(),
        meetingRequestId: form.meetingRequestId,
      }),
    );
    await refreshMeetings();
    setScheduleSuccessOpen(true);
  };

  const handleViewDetail = async (row: MeetingCalendarRow) => {
    try {
      const meeting = (await getMeetingById(row.id)) as DetailMeeting;
      setDetailMeeting(meeting);
      setDetailDialogOpen(true);
    } catch {
      setNotice(calendarLabels.loadDetailError);
    }
  };

  const handleEditMeeting = async (row: MeetingCalendarRow) => {
    try {
      const meeting = await getMeetingById(row.id);
      const meetingRequest = meeting.meetingRequest;
      const documentName =
        getDisplayFileName(getDocumentPath(meeting.documentReference), "") ||
        getDisplayFileName(meetingRequest?.meetingRequestLetter, "") ||
        getDisplayFileName(row.meetingRequest, "");

      // The API returns each agency with its stakeholder nested under
      // `.stakeholder`. Flatten it to { id, name, logo } so the meeting
      // detail/print can read the agency name and logo directly.
      const governmentAgencies: MeetingRequestGovernmentAgency[] = (
        (meetingRequest?.governmentAgencies ?? []) as Array<{
          stakeholderId?: number | null;
          stakeholder?: {
            id?: number | null;
            name?: string | null;
            logo?: string | null;
          } | null;
        }>
      ).map((agency) => ({
        id: agency.stakeholder?.id ?? agency.stakeholderId ?? 0,
        name: agency.stakeholder?.name ?? "-",
        logo: getMediaUrl(agency.stakeholder?.logo) || null,
      }));

      setEditMeeting({
        id: row.id,
        initialForm: mapApiMeetingToCreateForm(meeting),
        meetingRequestId: meetingRequest?.id ?? undefined,
        issues: mapMeetingCalendarIssues(
          meetingRequest?.issues,
          governmentAgencies,
        ),
        governmentAgencies,
        meetingRequest: meetingRequest?.id
          ? {
              id: meetingRequest.id,
              requestedBy:
                meetingRequest.requestedBy?.trim() ||
                meetingRequest.submittedBy?.trim() ||
                "-",
              requestedDate: meetingRequest.requestedDate?.trim() || "-",
              documentName,
              privateSectorWG: meetingRequest.privateSectorWG ?? undefined,
              submittedBy: meetingRequest.submittedBy ?? undefined,
            }
          : undefined,
      });
    } catch {
      setNotice(calendarLabels.loadEditError);
    }
  };

  const handleCreateMeetingSummary = (row: MeetingCalendarRow) => {
    const action = getMeetingSummaryAction(row.meetingSummaryId);

    router.push(
      action.path ?? `/ministry/meeting-summary/new?meetingId=${row.id}`,
    );
  };

  const handleCloseEditMeeting = () => {
    setEditMeeting(null);
  };

  const saveEditedMeeting = async (
    form: MeetingCreateForm,
    status: MeetingCalendarStatus,
    sendInvites = false,
  ) => {
    if (!editMeeting) {
      throw new Error("No meeting selected for editing.");
    }

    await updateMeeting(
      editMeeting.id,
      createMeetingSavePayload(form, {
        status,
        sendInvites,
        userId: getCurrentUserId(),
        meetingRequestId: editMeeting.meetingRequestId,
        fallbackTitle: form.title,
      }),
    );

    await refreshMeetings();
    setEditMeeting(null);

    if (status === "Scheduled" && sendInvites) {
      setScheduleSuccessOpen(true);
      return;
    }

    if (status === "Draft") {
      setToastMessage(t.detail.meetingDraftSuccess);
      return;
    }

    setToastMessage(calendarLabels.updatedSuccess);
  };

  const handleScheduleEditedMeeting = (form: MeetingCreateForm) => {
    return saveEditedMeeting(form, "Scheduled", true);
  };

  // Save Change preserves the meeting status and does not send invitations.
  const handleSaveChangeEditedMeeting = (form: MeetingCreateForm) => {
    return saveEditedMeeting(form, getMeetingStatusToKeep(form.status));
  };

  return (
    <Box
      sx={{
        "--mr-chip-bg": isDark ? "#1E3A5F" : "#EDF8FD",
        "--mr-chip-border": isDark ? "#4D87C7" : "#B6DBF6",
        "--mr-blue": isDark ? "#60A5FA" : "#1A64A8",
        minHeight: "calc(100dvh - 64px)",
        width: "100%",
        minWidth: 0,
        display: "flex",
        flexDirection: "column",
        px: { xs: 2, md: 3 },
        py: { xs: 2, md: 3 },
        color: "var(--calendar-text, #181d27)",
      }}
    >
      <Box
        sx={{
          mb: 4,
          display: "flex",
          alignItems: { xs: "stretch", sm: "center" },
          justifyContent: "space-between",
          flexDirection: { xs: "column", sm: "row" },
          gap: 2,
        }}
      >
        <Box>
          <Typography
            component="h1"
            sx={{
              color: isDark ? "#f3f4f6" : "#181d27",
              fontSize: { xs: 28, md: 32 },
              fontWeight: 600,
              lineHeight: 1.05,
              letterSpacing: "-0.02em",
            }}
          >
            {calendarLabels.title}
          </Typography>

          <Typography
            sx={{
              mt: 1.25,
              color: isDark ? "#a4a7ae" : "#717680",
              fontSize: 12,
              fontWeight: 500,
              lineHeight: 1,
            }}
          >
            {calendarLabels.subtitle}
          </Typography>
        </Box>

        <Button
          variant="contained"
          startIcon={<AddBoxOutlinedIcon sx={{ fontSize: 20 }} />}
          onClick={() => setCreateDialogOpen(true)}
          sx={{
            minWidth: { xs: 0, sm: 158 },
            width: { xs: "100%", sm: "auto" },
            height: 40,
            alignSelf: { xs: "stretch", sm: "center" },
            borderRadius: 1,
            bgcolor: isDark ? "#60a5fa" : "#1a64a8",
            boxShadow: "none",
            textTransform: "none",
            fontSize: 12,
            fontWeight: 500,
            "&:hover": {
              bgcolor: isDark ? "#60a5fa" : "#1a64a8",
              boxShadow: "none",
            },
          }}
        >
          {calendarLabels.createMeeting}
        </Button>
      </Box>

      <Box
        sx={{
          mb: 2.25,
          display: "flex",
          alignItems: { xs: "stretch", lg: "center" },
          justifyContent: "space-between",
          flexDirection: { xs: "column", lg: "row" },
          gap: 2,
        }}
      >
        <MinistryMeetingCalendarFilters
          filters={filters}
          onChange={handleFilterChange}
          yearOptions={yearOptions}
          labels={calendarLabels.filters}
          statusLabels={t.statusLabels}
        />

        <Box
          sx={{
            display: "flex",
            gap: { xs: 1, md: 2.75 },
            width: { xs: "100%", lg: "auto" },
            overflowX: { xs: "visible", lg: "auto" },
            flexWrap: { xs: "wrap", lg: "nowrap" },
          }}
        >
          <Button
            variant="contained"
            startIcon={<FormatListBulletedRoundedIcon sx={{ fontSize: 20 }} />}
            onClick={() => setActiveView("table")}
            aria-pressed={activeView === "table"}
            sx={{
              minWidth: { xs: 0, sm: 150 },
              width: { xs: "100%", sm: "auto" },
              flex: { xs: "1 1 140px", lg: "0 0 auto" },
              height: 40,
              flexShrink: 0,
              borderRadius: 1,
              bgcolor:
                activeView === "table"
                  ? isDark
                    ? "#60a5fa"
                    : "#1a64a8"
                  : isDark
                    ? "#182235"
                    : "#fafafa",
              color:
                activeView === "table"
                  ? "#ffffff"
                  : isDark
                    ? "#a4a7ae"
                    : "#717680",
              boxShadow: "none",
              textTransform: "none",
              fontSize: 12,
              fontWeight: 500,
              "&:hover": {
                bgcolor:
                  activeView === "table"
                    ? isDark
                      ? "#60a5fa"
                      : "#1a64a8"
                    : isDark
                      ? "#182235"
                      : "#fafafa",
                boxShadow: "none",
              },
            }}
          >
            {calendarLabels.allMeetings}
          </Button>

          <Button
            variant="text"
            startIcon={<CalendarMonthOutlinedIcon sx={{ fontSize: 20 }} />}
            onClick={() => setActiveView("calendar")}
            aria-pressed={activeView === "calendar"}
            sx={{
              minWidth: { xs: 0, sm: 150 },
              width: { xs: "100%", sm: "auto" },
              flex: { xs: "1 1 140px", lg: "0 0 auto" },
              height: 40,
              flexShrink: 0,
              borderRadius: 1,
              bgcolor:
                activeView === "calendar"
                  ? isDark
                    ? "#60a5fa"
                    : "#1a64a8"
                  : isDark
                    ? "#182235"
                    : "#fafafa",
              color:
                activeView === "calendar"
                  ? "#ffffff"
                  : isDark
                    ? "#a4a7ae"
                    : "#717680",
              boxShadow: "none",
              textTransform: "none",
              fontSize: 12,
              fontWeight: 500,
              "&:hover": {
                bgcolor:
                  activeView === "calendar"
                    ? isDark
                      ? "#60a5fa"
                      : "#1a64a8"
                    : isDark
                      ? "#182235"
                      : "#fafafa",
                boxShadow: "none",
              },
            }}
          >
            {calendarLabels.calendar}
          </Button>
        </Box>
      </Box>

      {activeView === "table" ? (
        <Box
          sx={{
            flex: 1,
            minHeight: 0,
            mt: 2,
            minWidth: 0,
            width: "100%",
            display: "flex",
            flexDirection: "column",
          }}
        >
          <MinistryMeetingCalendarTable
            rows={filteredRows}
            loading={loading}
            onView={handleViewDetail}
            onEdit={handleEditMeeting}
            onCreateMeetingSummary={handleCreateMeetingSummary}
            labels={calendarLabels}
            statusLabels={t.statusLabels}
          />
        </Box>
      ) : (
        <MinistryMeetingCalendarGrid
          key={`calendar-${filters.year.join("-") || "all"}`}
          rows={filteredRows}
          initialMonth={calendarInitialMonth}
          onView={handleViewDetail}
        />
      )}

      <MeetingDetailDialog
        open={detailDialogOpen}
        meeting={detailMeeting}
        onClose={() => setDetailDialogOpen(false)}
        labels={calendarLabels}
        statusLabels={t.statusLabels}
      />

      <ToastNotification
        open={scheduleSuccessOpen}
        onClose={() => setScheduleSuccessOpen(false)}
        message={t.detail.meetingScheduledSuccess}
        closeLabel={calendarLabels.detail.close}
        position="bottom-right"
        autoHideDuration={3200}
      />

      <ToastNotification
        open={Boolean(toastMessage)}
        message={toastMessage ?? ""}
        closeLabel={calendarLabels.detail.close}
        onClose={() => setToastMessage(null)}
      />

      <Snackbar
        open={Boolean(notice)}
        autoHideDuration={2600}
        message={notice}
        onClose={() => setNotice(null)}
      />

      <MeetingCreateDialog
        open={createDialogOpen}
        onClose={() => setCreateDialogOpen(false)}
        onSchedule={handleScheduleMeeting}
        onSaveDraft={handleSaveDraftMeeting}
        onIssueAdded={handleIssueAdded}
        confirmBeforeSchedule
        title={calendarLabels.createMeeting}
      />

      <MeetingCreateDialog
        key={editMeeting?.id ?? "edit-meeting"}
        open={Boolean(editMeeting)}
        initialForm={editMeeting?.initialForm}
        issues={editMeeting?.issues}
        governmentAgencies={editMeeting?.governmentAgencies}
        meetingRequest={editMeeting?.meetingRequest}
        onClose={handleCloseEditMeeting}
        onSchedule={handleScheduleEditedMeeting}
        onSaveChange={handleSaveChangeEditedMeeting}
        onIssueAdded={handleIssueAdded}
        isEditing
        confirmBeforeSchedule
        title={t.meetingCreate.editMeeting}
      />
    </Box>
  );
}
