"use client";

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

import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
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 { APP_PERMISSIONS } from "@/features/auth/permissions";
import {
  useIssueMatrixList,
  useIssueMatrixPlenaryEscalation,
  useIssueMatrixRowUpdate,
  useIssueMatrixSummary,
} from "@/features/pswg/issue-matrix/hook/use-issue-matrix";
import { useWgIssuesFilterOptions } from "@/features/pswg/working-group-issues/hook/use-working-group-issues";
import { exportIssueMatrix } from "@/features/pswg/issue-matrix/service/issue-matrix-service";

import {
  defaultIssueMatrixFilters,
  IssueMatrixFilters,
  type IssueMatrixFilterOptions,
  type IssueMatrixFilterState,
  type IssueMatrixView,
} from "./issue-matrix-filters";
import type { IssueMatrixRow } from "./issue-matrix-data";
import { IssueMatrixGrid } from "./issue-matrix-grid";
import { IssueMatrixHeader } from "./issue-matrix-header";
import { IssueMatrixStatusCards } from "./issue-matrix-status-cards";
import { IssueMatrixTable } from "./issue-matrix-table";
import type { IssueMatrixPlenaryEscalationControl } from "./issue-matrix-table-cells";
import {
  issueMatrixText,
  normalizeIssueMatrixLanguage,
  translateIssueMatrixValue,
} from "./issue-matrix-i18n";
import type {
  IssueMatrixAgencyOption,
  IssueMatrixEditControl,
} from "./issue-matrix-row-editors";

type PendingAgencyChange = {
  row: IssueMatrixRow;
  agency: IssueMatrixAgencyOption;
};

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

const EDITABLE_STATUS_CODES = new Set([
  "IN_PROGRESS",
  "NOT_ADDRESSED",
  "SOLVED",
]);

const CDC_STATUS_COLUMN_WIDTH = 160;

type IssueMatrixScreenProps = {
  // Where a row's "View Detail" link goes. CDC-GPSF passes its own base path
  // ("/cdc-gpsf/issue-matrix") so users stay inside their section.
  detailBasePath?: string;
  /** Filter keys hidden on this screen (CDC omits Progress Report / Attachment). */
  hiddenFilters?: Array<keyof IssueMatrixFilterState>;
  /** Enables the CDC table editors only on the CDC Issue Matrix route. */
  allowCdcRowEditing?: boolean;
};

export function IssueMatrixScreen({
  detailBasePath = "/pswg/issue-matrix",
  hiddenFilters = [],
  allowCdcRowEditing = false,
}: IssueMatrixScreenProps) {
  const theme = useTheme();
  const { language } = useAppLanguage();
  const { can } = usePermissions();
  const issueMatrixLanguage = normalizeIssueMatrixLanguage(language);
  const text = issueMatrixText[issueMatrixLanguage] ?? issueMatrixText.en;
  const canExportIssueMatrix = can(APP_PERMISSIONS.issueMatrix.export);
  const canViewPlenaryEscalation =
    allowCdcRowEditing && can(APP_PERMISSIONS.issueMatrix.read);
  const canEditCdcRows =
    allowCdcRowEditing && can(APP_PERMISSIONS.issueMatrix.update);
  const {
    rows,
    isLoading: isLoadingRows,
    error: rowsError,
  } = useIssueMatrixList();
  const { summary, isLoading: isLoadingSummary } = useIssueMatrixSummary();
  const {
    statuses,
    categories,
    agencies,
    isLoading: isLoadingExportLookups,
    error: exportLookupError,
  } = useWgIssuesFilterOptions();
  const {
    updateRow,
    isUpdating: isUpdatingRow,
    error: rowUpdateError,
    resetError: resetRowUpdateError,
  } = useIssueMatrixRowUpdate();
  const {
    setPlenaryEscalation,
    isUpdating: isUpdatingEscalation,
    error: escalationError,
    resetError: resetEscalationError,
  } = useIssueMatrixPlenaryEscalation();

  const [search, setSearch] = useState("");
  const [isExporting, setIsExporting] = useState(false);
  const [exportError, setExportError] = useState("");
  const [view, setView] = useState<IssueMatrixView>("list");
  const [pendingAgencyChange, setPendingAgencyChange] =
    useState<PendingAgencyChange | null>(null);
  const [pendingStatusChange, setPendingStatusChange] =
    useState<PendingStatusChange | null>(null);
  const [pendingPlenaryEscalation, setPendingPlenaryEscalation] = useState<{
    row: IssueMatrixRow;
    escalated: boolean;
  } | null>(null);
  const [toastMessage, setToastMessage] = useState<string | null>(null);
  const [filters, setFilters] = useState<IssueMatrixFilterState>({
    ...defaultIssueMatrixFilters,
  });

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

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

      return options;
    };

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

  const primaryAgencyLogos = useMemo(() => {
    const logos: Record<string, string | null> = {};

    for (const row of rows) {
      if (!row.primaryAgency || logos[row.primaryAgency] !== undefined) {
        continue;
      }

      logos[row.primaryAgency] = row.primaryAgencyImage;
    }

    return logos;
  }, [rows]);

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

  const editableStatusOptions = useMemo(
    () =>
      statuses.filter((status) =>
        EDITABLE_STATUS_CODES.has(status.code?.trim().toUpperCase() ?? ""),
      ),
    [statuses],
  );

  const agencyOptions = useMemo(
    () =>
      agencies.map((agency) => ({
        label: agency.name,
        value: String(agency.id),
        logo: agency.logo ?? null,
      })),
    [agencies],
  );

  const handleAgencySave = useCallback(
    (row: IssueMatrixRow, agency: IssueMatrixAgencyOption) => {
      resetRowUpdateError();
      setPendingAgencyChange({ row, agency });
    },
    [resetRowUpdateError],
  );

  const handleStatusSave = useCallback(
    (row: IssueMatrixRow, statusId: number, statusName: string) => {
      resetRowUpdateError();
      const status = editableStatusOptions.find((item) => item.id === statusId);

      setPendingStatusChange({
        row,
        statusId,
        statusName,
        statusCode: status?.code ?? "",
      });
    },
    [editableStatusOptions, resetRowUpdateError],
  );

  const handlePlenaryEscalationToggle = useCallback(
    (row: IssueMatrixRow, escalated: boolean) => {
      resetRowUpdateError();
      resetEscalationError();
      setPendingPlenaryEscalation({ row, escalated });
    },
    [resetEscalationError, resetRowUpdateError],
  );

  const handleConfirmAgencyChange = useCallback(() => {
    if (!pendingAgencyChange) return;

    const { row, agency } = pendingAgencyChange;

    updateRow(
      {
        issueId: row.id,
        governmentAgencyIds: [agency.id],
        primaryAgency: agency,
      },
      {
        onSuccess: () => {
          setPendingAgencyChange(null);
          setToastMessage(text.rowUpdateToast.ministryUpdated);
        },
        onError: () => {
          setPendingAgencyChange(null);
        },
      },
    );
  }, [pendingAgencyChange, text.rowUpdateToast.ministryUpdated, updateRow]);

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

    const { row, statusId, statusName, statusCode } = pendingStatusChange;

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

  const editControl = useMemo<IssueMatrixEditControl | undefined>(() => {
    if (!allowCdcRowEditing) return undefined;

    return {
      canEdit: canEditCdcRows,
      isUpdating: isUpdatingRow,
      agencyOptions,
      statusOptions: editableStatusOptions.map((status) => ({
        ...status,
        code: status.code ?? "",
      })),
      onAgencySave: handleAgencySave,
      onStatusSave: handleStatusSave,
    };
  }, [
    agencyOptions,
    allowCdcRowEditing,
    canEditCdcRows,
    editableStatusOptions,
    handleAgencySave,
    handleStatusSave,
    isUpdatingRow,
  ]);

  const plenaryEscalationControl = useMemo<
    IssueMatrixPlenaryEscalationControl | undefined
  >(() => {
    if (!canViewPlenaryEscalation) return undefined;

    return {
      canEscalate: canViewPlenaryEscalation && canEditCdcRows,
      isUpdating: isUpdatingEscalation,
      onToggle: handlePlenaryEscalationToggle,
    };
  }, [
    canEditCdcRows,
    canViewPlenaryEscalation,
    handlePlenaryEscalationToggle,
    isUpdatingEscalation,
  ]);

  const handleConfirmPlenaryEscalation = useCallback(() => {
    if (!pendingPlenaryEscalation) return;

    const { row, escalated } = pendingPlenaryEscalation;

    setPlenaryEscalation(
      { issueId: row.id, escalated },
      {
        onSuccess: () => {
          setPendingPlenaryEscalation(null);
          setToastMessage(
            escalated
              ? text.plenaryEscalationToast.escalated
              : text.plenaryEscalationToast.removed,
          );
        },
        onError: () => {
          setPendingPlenaryEscalation(null);
        },
      },
    );
  }, [
    pendingPlenaryEscalation,
    setPlenaryEscalation,
    text.plenaryEscalationToast.escalated,
    text.plenaryEscalationToast.removed,
  ]);

  const handleExport = async () => {
    setExportError("");
    setIsExporting(true);

    try {
      await exportIssueMatrix({
        language: issueMatrixLanguage,
        search,
        selectedWorkingGroups: filters.workingGroup,
        selectedStatuses: filters.status,
        selectedCategories: filters.category,
        selectedPrimaryAgencies: filters.primaryAgency,
        selectedYears: filters.year,
        selectedAttachments: filters.attachment,
        rows,
        statuses,
        categories,
        agencies,
      });
    } catch (error) {
      setExportError(
        error instanceof Error
          ? error.message
          : "Unable to export issue matrix.",
      );
    } finally {
      setIsExporting(false);
    }
  };

  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.sourceOfVerification,
          row.status,
          row.year,
          row.progressReport,
        ]
          .join(" ")
          .toLowerCase()
          .includes(normalizedSearch);

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

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

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

      const matchesPrimaryAgency =
        filters.primaryAgency.length === 0 ||
        filters.primaryAgency.includes(row.primaryAgency);

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

      const matchesProgressReport =
        filters.progressReport.length === 0 ||
        filters.progressReport.includes(row.progressReport);

      const matchesAttachment =
        filters.attachment.length === 0 ||
        (filters.attachment.includes("Yes") && row.hasAttachment) ||
        (filters.attachment.includes("No") && !row.hasAttachment);

      return (
        matchesSearch &&
        matchesWorkingGroup &&
        matchesStatus &&
        matchesCategory &&
        matchesPrimaryAgency &&
        matchesYear &&
        matchesProgressReport &&
        matchesAttachment
      );
    });
  }, [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",
        }}
      >
        <IssueMatrixHeader
          search={search}
          canExport={canExportIssueMatrix}
          language={issueMatrixLanguage}
          exportDisabled={
            !canExportIssueMatrix ||
            isLoadingRows ||
            isLoadingExportLookups ||
            Boolean(exportLookupError) ||
            rows.length === 0
          }
          exportLoading={isExporting}
          onExport={handleExport}
          onSearchChange={setSearch}
        />

        {exportError ? (
          <Typography
            sx={{
              mb: 2,
              color: "#f04438",
              fontSize: 13,
              fontWeight: 500,
            }}
          >
            {exportError}
          </Typography>
        ) : null}

        {rowUpdateError || escalationError ? (
          <Typography
            sx={{
              mb: 2,
              color: "#f04438",
              fontSize: 13,
              fontWeight: 500,
            }}
          >
            {rowUpdateError ?? text.plenaryEscalationError}
          </Typography>
        ) : null}

        <IssueMatrixFilters
          filters={filters}
          language={issueMatrixLanguage}
          options={filterOptions}
          primaryAgencyLogos={primaryAgencyLogos}
          hiddenFilters={hiddenFilters}
          onChange={handleFilterChange}
          {...(allowCdcRowEditing
            ? { view, onViewChange: setView }
            : {})}
        />

        <Box sx={{ mb: 3 }}>
          <IssueMatrixStatusCards
            language={issueMatrixLanguage}
            summary={summary}
          />
        </Box>

        {allowCdcRowEditing && view === "grid" ? (
          <IssueMatrixGrid
            rows={filteredRows}
            language={issueMatrixLanguage}
            detailBasePath={detailBasePath}
            loading={isLoadingRows || isLoadingSummary}
            error={rowsError}
          />
        ) : (
          <IssueMatrixTable
            rows={filteredRows}
            language={issueMatrixLanguage}
            loading={isLoadingRows || isLoadingSummary}
            error={rowsError}
            detailBasePath={detailBasePath}
            editControl={editControl}
            statusColumnWidth={
              allowCdcRowEditing ? CDC_STATUS_COLUMN_WIDTH : undefined
            }
            showPlenaryEscalation={canViewPlenaryEscalation}
            plenaryEscalationControl={plenaryEscalationControl}
            placeDateOfSolutionAfterPrimaryAgency={allowCdcRowEditing}
          />
        )}
      </Box>

      <AlertDialog
        open={Boolean(pendingAgencyChange)}
        title={text.ministryChangeDialog.title}
        description={text.ministryChangeDialog.description(
          pendingAgencyChange?.agency.name ?? "",
        )}
        confirmLabel={text.ministryChangeDialog.confirm}
        cancelLabel={text.ministryChangeDialog.cancel}
        loading={isUpdatingRow}
        onConfirm={handleConfirmAgencyChange}
        onCancel={() => setPendingAgencyChange(null)}
      />

      <AlertDialog
        open={Boolean(pendingStatusChange)}
        title={text.statusChangeDialog.title}
        description={text.statusChangeDialog.description(
          pendingStatusChange
            ? translateIssueMatrixValue(
                pendingStatusChange.statusName,
                issueMatrixLanguage,
              )
            : "",
        )}
        confirmLabel={text.statusChangeDialog.confirm}
        cancelLabel={text.statusChangeDialog.cancel}
        loading={isUpdatingRow}
        onConfirm={handleConfirmStatusChange}
        onCancel={() => setPendingStatusChange(null)}
      />

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

      <ToastNotification
        open={Boolean(toastMessage)}
        message={toastMessage ?? ""}
        position="bottom-right"
        closeLabel={text.plenaryEscalationToast.close}
        onClose={() => setToastMessage(null)}
      />
    </Box>
  );
}
