"use client";

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

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

import { useAppLanguage } from "@/components/providers/app-language-provider";
import { AlertDialog } from "@/components/ui/alert-dialog";
import { ToastNotification } from "@/components/ui/toast-notification";
import { usePermissions } from "@/features/auth/hook/use-permissions";
import { canUseCdcIssueMatrix } from "@/features/cdc/cdc-issue-matrix/cdc-issue-matrix-permissions";
import { CreateIssueDialog } from "@/features/pswg/working-group-issues/components/create-issuses";

import {
  useCdcIssueMatrixList,
  useCdcIssueMatrixPlenaryEscalation,
  useCdcIssueMatrixRowUpdate,
  useCdcIssueMatrixSummary,
  useDeleteCdcIssue,
} from "../hook/use-cdc-issue-matrix";
import { useCdcIssueMatrixFormOptions } from "../hook/use-cdc-issue-form";

import {
  CdcIssueMatrixFilters,
  defaultCdcIssueMatrixFilters,
  type CdcIssueMatrixFilterOptions,
  type CdcIssueMatrixFilterState,
} from "./cdc-issue-matrix-filters";
import { CdcIssueMatrixGrid } from "./cdc-issue-matrix-grid";
import { CdcIssueMatrixHeader } from "./cdc-issue-matrix-header";
import { CdcIssueMatrixStatusCards } from "./cdc-issue-matrix-status-cards";
import { CdcIssueMatrixTable } from "./cdc-issue-matrix-table";
import type { CdcIssueMatrixView } from "./cdc-issue-matrix-view-toggle";
import {
  CDC_ISSUE_MATRIX_STATUS_FILTER_OPTIONS,
  type CdcIssueMatrixRow,
} from "./cdc-issue-matrix-data";
import {
  cdcIssueMatrixText,
  normalizeCdcIssueMatrixLanguage,
} from "./cdc-issue-matrix-i18n";

/** The escalation change waiting for the user to confirm it. */
type PendingPlenaryEscalation = {
  issueId: number;
  escalated: boolean;
};

type PendingStatusChange = {
  row: CdcIssueMatrixRow;
  statusId: number;
  statusName: string;
};

type PendingMinistryChange = {
  row: CdcIssueMatrixRow;
  agencies: CdcIssueMatrixRow["agencies"];
};

export function CdcIssueMatrixScreen() {
  const theme = useTheme();
  const { language } = useAppLanguage();
  const matrixLanguage = normalizeCdcIssueMatrixLanguage(language);
  const text = cdcIssueMatrixText[matrixLanguage] ?? cdcIssueMatrixText.en;

  const {
    rows,
    isLoading: isLoadingRows,
    error: rowsError,
  } = useCdcIssueMatrixList();
  const { summary, isLoading: isLoadingSummary } = useCdcIssueMatrixSummary();
  const { can } = usePermissions();
  const {
    setPlenaryEscalation,
    isUpdating: isUpdatingEscalation,
    error: escalationError,
    resetError: resetEscalationError,
  } = useCdcIssueMatrixPlenaryEscalation();
  const {
    updateRow,
    isUpdating: isUpdatingRow,
    error: rowUpdateError,
    resetError: resetRowUpdateError,
  } = useCdcIssueMatrixRowUpdate();

  // Only CDC or CEFP users may edit rows straight from the table.
  const canEscalateToPlenary = canUseCdcIssueMatrix(can, "update");

  const [pendingEscalation, setPendingEscalation] =
    useState<PendingPlenaryEscalation | null>(null);
  const [pendingStatusChange, setPendingStatusChange] =
    useState<PendingStatusChange | null>(null);
  const [pendingMinistryChange, setPendingMinistryChange] =
    useState<PendingMinistryChange | null>(null);
  const [ministrySelectionResetKey, setMinistrySelectionResetKey] = useState(0);
  const [editTarget, setEditTarget] = useState<CdcIssueMatrixRow | null>(null);
  const [deleteTarget, setDeleteTarget] =
    useState<CdcIssueMatrixRow | null>(null);
  const [toastMessage, setToastMessage] = useState<string | null>(null);
  const deleteCdcIssueMutation = useDeleteCdcIssue();

  // Ticking the checkbox only opens the confirmation; the change is saved once
  // the user confirms it.
  const handlePlenaryEscalationToggle = useCallback(
    (issueId: number, escalated: boolean) => {
      setPendingEscalation({ issueId, escalated });
    },
    [],
  );

  const handleConfirmPlenaryEscalation = () => {
    if (!pendingEscalation) return;

    const { issueId, escalated } = pendingEscalation;

    setPlenaryEscalation(
      { issueId, escalated },
      {
        onSuccess: () => {
          setToastMessage(
            escalated
              ? text.plenaryEscalationToast.escalated
              : text.plenaryEscalationToast.removed,
          );
          setPendingEscalation(null);
        },
        onError: () => {
          setPendingEscalation(null);
        },
      },
    );
  };

  const plenaryEscalationControl = useMemo(
    () => ({
      canEscalate: canEscalateToPlenary,
      isUpdating: isUpdatingEscalation,
      onToggle: handlePlenaryEscalationToggle,
    }),
    [canEscalateToPlenary, isUpdatingEscalation, handlePlenaryEscalationToggle],
  );

  // The ministry and status pickers in the table share the same permission and
  // the same lookup lists as the issue dialog.
  const { agencies } = useCdcIssueMatrixFormOptions(canEscalateToPlenary);

  const agencyOptions = useMemo(
    () =>
      agencies.map((agency) => ({
        label: agency.name,
        value: String(agency.id),
        // Always present, even when null: the dropdown only draws an avatar
        // when the option carries a logo key.
        logo: agency.logo ?? null,
      })),
    [agencies],
  );

  const handleMinistrySave = useCallback(
    (row: CdcIssueMatrixRow, nextAgencies: CdcIssueMatrixRow["agencies"]) => {
      setPendingMinistryChange({ row, agencies: nextAgencies });
    },
    [],
  );

  const resetPendingMinistryChange = useCallback(() => {
    setPendingMinistryChange(null);
    setMinistrySelectionResetKey((current) => current + 1);
  }, []);

  const handleConfirmMinistryChange = useCallback(() => {
    if (!pendingMinistryChange) return;

    const { row, agencies } = pendingMinistryChange;

    updateRow(
      {
        issueId: row.issueId,
        governmentAgencyIds: agencies.map((agency) => agency.id),
        agencies,
      },
      {
        onSuccess: () => {
          resetPendingMinistryChange();
          setToastMessage(text.rowUpdateToast.ministryUpdated);
        },
        onError: resetPendingMinistryChange,
      },
    );
  }, [
    pendingMinistryChange,
    resetPendingMinistryChange,
    text.rowUpdateToast.ministryUpdated,
    updateRow,
  ]);

  const handleStatusSave = useCallback(
    (row: CdcIssueMatrixRow, statusId: number, statusName: string) => {
      setPendingStatusChange({ row, statusId, statusName });
    },
    [],
  );

  const handleConfirmStatusChange = useCallback(() => {
    if (!pendingStatusChange) return;

    const { row, statusId, statusName } = pendingStatusChange;

    updateRow(
      {
        issueId: row.issueId,
        issueStatusId: statusId,
        status: statusName as CdcIssueMatrixRow["status"],
      },
      {
        onSuccess: () => {
          setPendingStatusChange(null);
          setToastMessage(text.rowUpdateToast.statusUpdated);
        },
        onError: () => {
          setPendingStatusChange(null);
        },
      },
    );
  }, [pendingStatusChange, text.rowUpdateToast.statusUpdated, updateRow]);

  const handleCancelStatusChange = useCallback(() => {
    setPendingStatusChange(null);
  }, []);

  const ministryEditControl = useMemo(
    () => ({
      canEdit: canEscalateToPlenary,
      isUpdating: isUpdatingRow,
      agencyOptions,
      selectionResetKey: ministrySelectionResetKey,
      onSave: handleMinistrySave,
    }),
    [
      canEscalateToPlenary,
      isUpdatingRow,
      agencyOptions,
      ministrySelectionResetKey,
      handleMinistrySave,
    ],
  );

  const statusEditControl = useMemo(
    () => ({
      canEdit: canEscalateToPlenary,
      isUpdating: isUpdatingRow,
      onSave: handleStatusSave,
    }),
    [canEscalateToPlenary, isUpdatingRow, handleStatusSave],
  );

  // One snackbar covers both row edits and escalation, so clear both.
  const clearRowErrors = useCallback(() => {
    resetEscalationError();
    resetRowUpdateError();
  }, [resetEscalationError, resetRowUpdateError]);

  const handleDeleteIssue = useCallback(async () => {
    if (!deleteTarget) return;

    try {
      await deleteCdcIssueMutation.mutateAsync(deleteTarget.issueId);
      setDeleteTarget(null);
      setToastMessage(text.issueDeleted);
    } catch {
      setDeleteTarget(null);
      setToastMessage(text.issueDeleteFailed);
    }
  }, [deleteCdcIssueMutation, deleteTarget, text]);

  const [search, setSearch] = useState("");
  const [view, setView] = useState<CdcIssueMatrixView>("list");
  // Controls the slide-in "Add Issue" drawer opened by the New button.
  const [isAddIssueOpen, setIsAddIssueOpen] = useState(false);
  const [filters, setFilters] = useState<CdcIssueMatrixFilterState>({
    ...defaultCdcIssueMatrixFilters,
  });

  const filterOptions = useMemo<CdcIssueMatrixFilterOptions>(() => {
    const getUniqueOptions = (values: string[], sortDescending = false) => {
      const uniqueOptions = Array.from(
        new Set(values.filter(Boolean).filter((value) => value !== "-")),
      );

      uniqueOptions.sort((firstValue, secondValue) =>
        sortDescending
          ? Number(secondValue) - Number(firstValue)
          : firstValue.localeCompare(secondValue),
      );

      return uniqueOptions;
    };

    return {
      category: getUniqueOptions(rows.map((row) => row.category)),
      status: [...CDC_ISSUE_MATRIX_STATUS_FILTER_OPTIONS],
      workingGroup: getUniqueOptions(rows.map((row) => row.workingGroup)),
      year: getUniqueOptions(
        rows.map((row) => row.year),
        true,
      ),
      plenaryEscalation: ["Yes", "No"],
    };
  }, [rows]);

  const handleFilterChange = (
    key: keyof CdcIssueMatrixFilterState,
    value: string[],
  ) => {
    setFilters((prev) => ({
      ...prev,
      [key]: value,
    }));
  };

  const filteredRows = useMemo(() => {
    const normalizedSearch = search.trim().toLowerCase();

    return rows.filter((row) => {
      const matchesSearch =
        normalizedSearch === "" ||
        [
          row.issue,
          row.category,
          row.issueDescription,
          row.recommendation,
          row.governmentDecision,
          row.primaryAgency,
          row.workingGroup,
          row.status,
          row.year,
        ]
          .join(" ")
          .toLowerCase()
          .includes(normalizedSearch);

      const matchesCategory =
        filters.category.length === 0 ||
        filters.category.includes(row.category);

      const matchesStatus =
        filters.status.length === 0 || filters.status.includes(row.status);

      const matchesWorkingGroup =
        filters.workingGroup.length === 0 ||
        filters.workingGroup.includes(row.workingGroup);

      const matchesYear =
        filters.year.length === 0 || filters.year.includes(row.year);

      const matchesPlenaryEscalation =
        filters.plenaryEscalation.length === 0 ||
        (filters.plenaryEscalation.includes("Yes") && row.plenaryEscalation) ||
        (filters.plenaryEscalation.includes("No") && !row.plenaryEscalation);

      return (
        matchesSearch &&
        matchesCategory &&
        matchesStatus &&
        matchesWorkingGroup &&
        matchesYear &&
        matchesPlenaryEscalation
      );
    });
  }, [search, filters, rows]);

  return (
    <Box
      sx={{
        minHeight: "calc(100dvh - 64px)",
        width: "100%",
        display: "flex",
        flexDirection: "column",
        bgcolor: theme.palette.background.default,
        color: theme.palette.text.primary,
        px: { xs: 2, md: 3 },
        py: { xs: 2, md: 3 },
      }}
    >
      <Box
        sx={{
          flex: 1,
          minHeight: 0,
          width: "100%",
          display: "flex",
          flexDirection: "column",
        }}
      >
        <CdcIssueMatrixHeader
          search={search}
          language={matrixLanguage}
          exportDisabled
          onSearchChange={setSearch}
          onNewIssue={() => setIsAddIssueOpen(true)}
        />

        <CdcIssueMatrixFilters
          filters={filters}
          language={matrixLanguage}
          options={filterOptions}
          view={view}
          onChange={handleFilterChange}
          onViewChange={setView}
        />

        <Box sx={{ mb: 3 }}>
          <CdcIssueMatrixStatusCards
            language={matrixLanguage}
            summary={summary}
          />
        </Box>

        {view === "list" ? (
          <CdcIssueMatrixTable
            rows={filteredRows}
            language={matrixLanguage}
            loading={isLoadingRows || isLoadingSummary}
            error={rowsError}
            showRemark
            plenaryEscalationControl={plenaryEscalationControl}
            ministryEditControl={ministryEditControl}
            statusEditControl={statusEditControl}
            onEdit={setEditTarget}
            onRemove={setDeleteTarget}
          />
        ) : (
          <CdcIssueMatrixGrid
            rows={filteredRows}
            language={matrixLanguage}
            loading={isLoadingRows || isLoadingSummary}
            error={rowsError}
            onEdit={setEditTarget}
            onRemove={setDeleteTarget}
          />
        )}
      </Box>

      <CreateIssueDialog
        mode="cdc"
        open={isAddIssueOpen}
        onCreated={() => setToastMessage(text.issueCreated)}
        onClose={() => setIsAddIssueOpen(false)}
      />

      {editTarget ? (
        <CreateIssueDialog
          mode="cdc"
          issueId={editTarget.issueId}
          open
          onSaved={() => {
            setEditTarget(null);
            setToastMessage(text.issueUpdated);
          }}
          onClose={() => setEditTarget(null)}
        />
      ) : null}

      <AlertDialog
        open={Boolean(deleteTarget)}
        title={text.deleteCdcIssue}
        description={text.deleteCdcIssueQuestion}
        confirmLabel={text.deleteCdcIssue}
        cancelLabel={text.cancel}
        confirmColor="danger"
        loading={deleteCdcIssueMutation.isPending}
        onConfirm={() => void handleDeleteIssue()}
        onCancel={() => setDeleteTarget(null)}
      />

      <AlertDialog
        open={Boolean(pendingEscalation)}
        title={
          pendingEscalation?.escalated
            ? text.plenaryEscalationDialog.escalateTitle
            : text.plenaryEscalationDialog.removeTitle
        }
        description={
          pendingEscalation?.escalated
            ? text.plenaryEscalationDialog.escalateDescription
            : text.plenaryEscalationDialog.removeDescription
        }
        confirmLabel={
          pendingEscalation?.escalated
            ? text.plenaryEscalationDialog.escalateConfirm
            : text.plenaryEscalationDialog.removeConfirm
        }
        cancelLabel={text.plenaryEscalationDialog.cancel}
        confirmColor={pendingEscalation?.escalated ? "primary" : "danger"}
        loading={isUpdatingEscalation}
        onConfirm={handleConfirmPlenaryEscalation}
        onCancel={() => setPendingEscalation(null)}
      />

      <AlertDialog
        open={Boolean(pendingStatusChange)}
        title={text.statusChangeDialog.title}
        description={
          pendingStatusChange
            ? text.statusChangeDialog.description(pendingStatusChange.statusName)
            : undefined
        }
        confirmLabel={text.statusChangeDialog.confirm}
        cancelLabel={text.statusChangeDialog.cancel}
        loading={isUpdatingRow}
        onConfirm={handleConfirmStatusChange}
        onCancel={handleCancelStatusChange}
      />

      <AlertDialog
        open={Boolean(pendingMinistryChange)}
        title={text.ministryChangeDialog.title}
        description={
          pendingMinistryChange
            ? text.ministryChangeDialog.description(
                pendingMinistryChange.agencies[0]?.name ?? "-",
              )
            : undefined
        }
        confirmLabel={text.ministryChangeDialog.confirm}
        cancelLabel={text.ministryChangeDialog.cancel}
        loading={isUpdatingRow}
        onConfirm={handleConfirmMinistryChange}
        onCancel={resetPendingMinistryChange}
      />

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

      <Snackbar
        open={Boolean(escalationError ?? rowUpdateError)}
        autoHideDuration={5000}
        anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
        onClose={clearRowErrors}
      >
        <Alert severity="error" onClose={clearRowErrors}>
          {escalationError
            ? text.plenaryEscalationError
            : text.rowUpdateError}
        </Alert>
      </Snackbar>
    </Box>
  );
}
