"use client";

import { useRef, useState } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";

import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew";
import Alert from "@mui/material/Alert";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
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 { AlertDialog } from "@/components/ui/alert-dialog";
import { AppSecondaryButton } from "@/components/ui/button";
import { ExportButton } from "@/components/ui/export-button";
import type { ExportFormat } from "@/components/ui/export-format-menu";
import { ToastNotification } from "@/components/ui/toast-notification";
import { formatDate } from "@/lib/date-utils";
import { formatNumber } from "@/lib/number-utils";
import {
  buildCsvBlob,
  buildXlsxBlob,
  downloadBlob,
  downloadNodeAsPng,
  type ExportTable,
} from "@/lib/export-file";
import { AgencyStatusCard } from "@/features/ministry/dashboard/components/charts/agency-status-card";
import { CategoryIssuesCard } from "@/features/ministry/dashboard/components/charts/category-issues-card";
import { WorkingGroupStatusCard } from "@/features/ministry/dashboard/components/charts/dashboard-status-card";
import { OverallStatusCard } from "@/features/ministry/dashboard/components/charts/overall-status-card";
import { DashboardPageContainer } from "@/features/ministry/dashboard/components/dashboard-page-container";

import { useProgressReport } from "../../hook/use-progress-reports";
import {
  normalizeProgressReportLanguage,
  progressReportText,
} from "../../progress-report-i18n";

import {
  buildDraftDashboardExportParts,
  buildDraftDashboardFilename,
} from "./draft-dashboard-export";
import {
  mapAgenciesToRows,
  mapCardsToDonut,
  mapCardsToStatusCounts,
  mapCardsToSummary,
  mapCategoriesToRows,
  mapWorkingGroupsToRows,
} from "./draft-dashboard-mapper";
import type { DraftDashboardStage } from "./draft-dashboard-service";
import { DraftDashboardSummaryCards } from "./draft-dashboard-summary-cards";
import {
  useDraftDashboard,
  useGenerateDraftDashboard,
  usePublishLiveDashboard,
} from "./use-draft-dashboard";

type DraftDashboardScreenProps = {
  // The same page serves the draft and the final dashboard; only the saved
  // numbers and a few words differ.
  stage?: DraftDashboardStage;
};

export function DraftDashboardScreen({
  stage = "draft",
}: DraftDashboardScreenProps = {}) {
  const theme = useTheme();
  const params = useParams<{ id: string }>();
  const reportId = params.id ?? "";
  const { language } = useAppLanguage();
  const labels = progressReportText[normalizeProgressReportLanguage(language)];
  const { report } = useProgressReport(reportId);
  const isFinal = stage === "final";
  const { dashboard, isValidId, isLoading, error } = useDraftDashboard(
    reportId,
    stage,
  );
  const { mutateAsync: generateDraftDashboard, isPending: isGenerating } =
    useGenerateDraftDashboard(stage);
  const { mutateAsync: publishLiveDashboard, isPending: isPublishing } =
    usePublishLiveDashboard();
  const [toastMessage, setToastMessage] = useState("");
  const [confirmOpen, setConfirmOpen] = useState(false);
  const [liveConfirmOpen, setLiveConfirmOpen] = useState(false);

  // What each Image export takes a picture of: the whole block for the page
  // button, and one card for each card button.
  const contentRef = useRef<HTMLDivElement | null>(null);
  const overallRef = useRef<HTMLDivElement | null>(null);
  const agencyRef = useRef<HTMLDivElement | null>(null);
  const workingGroupRef = useRef<HTMLDivElement | null>(null);
  const categoryRef = useRef<HTMLDivElement | null>(null);
  const [exporting, setExporting] = useState(false);
  const [actionError, setActionError] = useState("");

  // Recalculates the numbers from what the ministries submitted and saves
  // them as the draft, so the page then shows the saved figures. It replaces
  // the draft saved before, which is why it asks first.
  const handleGenerate = async () => {
    if (!isValidId || isGenerating) return;

    setConfirmOpen(false);
    setActionError("");

    try {
      await generateDraftDashboard(Number(reportId));
      setToastMessage(
        isFinal
          ? labels.draftDashboard.finalGenerated
          : labels.successMessages.draftDashboardGenerated,
      );
    } catch (generateError) {
      setActionError(
        generateError instanceof Error
          ? generateError.message
          : isFinal
            ? labels.draftDashboard.finalFailed
            : labels.errorMessages.draftDashboardFailed,
      );
    }
  };

  // "Live": hands the saved final numbers to the Ministry, PSWG, CDC and CEFP
  // dashboards. Nothing is recalculated, so what they see is what is on
  // screen here.
  const handlePublishLive = async () => {
    if (!isValidId || isPublishing) return;

    setLiveConfirmOpen(false);
    setActionError("");

    try {
      await publishLiveDashboard(Number(reportId));
      setToastMessage(labels.draftDashboard.livePublished);
    } catch (publishError) {
      setActionError(
        publishError instanceof Error
          ? publishError.message
          : labels.draftDashboard.liveFailed,
      );
    }
  };

  // The charts only render once the numbers are here, so every card reads
  // from the same response.
  const cards = dashboard?.cards ?? null;
  const pageError = !isValidId
    ? labels.draftDashboard.invalidReportId
    : error || (!isLoading && !cards ? labels.draftDashboard.loadError : null);

  // Rows are built once and shared by the charts and the export, so a
  // downloaded file always matches what is on screen.
  const agencyRows = mapAgenciesToRows(dashboard?.byPrimaryAgency ?? []);
  const workingGroupRows = mapWorkingGroupsToRows(
    dashboard?.byWorkingGroup ?? [],
  );
  const categoryRows = mapCategoriesToRows(dashboard?.byCategory ?? []);

  // The tables behind every Export button on this page.
  const exportParts = cards
    ? buildDraftDashboardExportParts({
        cards,
        agencyRows,
        workingGroupRows,
        categoryRows,
      })
    : null;

  // CSV and XLSX download the numbers; Image takes a picture of `node`.
  // `part` is the middle of the filename, so each card gets its own file.
  const runExport = async (
    format: ExportFormat,
    tables: ExportTable[],
    node: HTMLElement | null,
    part?: string,
  ) => {
    if (exporting) return;

    setExporting(true);
    setActionError("");

    try {
      if (format === "CSV") {
        downloadBlob(
          buildCsvBlob(tables),
          buildDraftDashboardFilename("csv", part, stage),
        );
      } else if (format === "XLSX") {
        const blob = await buildXlsxBlob(tables);
        downloadBlob(blob, buildDraftDashboardFilename("xlsx", part, stage));
      } else if (node) {
        await downloadNodeAsPng(
          node,
          buildDraftDashboardFilename("png", part, stage),
          theme.palette.background.default,
        );
      }
    } catch (downloadError) {
      setActionError(
        downloadError instanceof Error
          ? downloadError.message
          : labels.draftDashboard.exportError,
      );
    } finally {
      setExporting(false);
    }
  };

  const semesterLabel =
    report?.semester === "S2"
      ? labels.draftDashboard.semesterTwo
      : labels.draftDashboard.semesterOne;
  const title = isFinal
    ? labels.draftDashboard.finalTitle(semesterLabel)
    : labels.draftDashboard.title(semesterLabel);
  const statusLabels = labels.draftDashboard.cards;
  // Every number on the page is written in the current language's digits.
  const toPageNumber = (value: number) => formatNumber(value, language);
  // Back always returns to the progress-report list.
  const backHref = "/cdc-gpsf/progress-reports";

  return (
    <DashboardPageContainer>
      <Box
        sx={{
          display: "flex",
          flexDirection: "column",
          gap: 3,
          color: theme.palette.text.primary,
        }}
      >
        <Box
          sx={{
            display: "flex",
            flexWrap: "wrap",
            alignItems: "center",
            justifyContent: "space-between",
            gap: 2,
          }}
        >
          <Box
            sx={{
              display: "flex",
              alignItems: "center",
              gap: { xs: 1.5, md: "23px" },
              minWidth: 0,
            }}
          >
            <AppSecondaryButton
              component={Link}
              href={backHref}
              startIcon={<ArrowBackIosNewIcon sx={{ fontSize: 14 }} />}
              sx={{
                width: 104,
                minWidth: 104,
                height: 40,
                bgcolor: "transparent",
                borderColor: "transparent",
                color: theme.palette.text.secondary,
                "&:hover": {
                  bgcolor: theme.palette.action.hover,
                  borderColor: "transparent",
                },
              }}
            >
              {labels.draftDashboard.back}
            </AppSecondaryButton>

            <Typography
              sx={{
                fontSize: { xs: 20, md: 24 },
                fontWeight: 700,
                lineHeight: 1.2,
                color: theme.palette.text.primary,
              }}
            >
              {title}
            </Typography>
          </Box>

          <Box
            sx={{
              display: "flex",
              flexDirection: "column",
              alignItems: "flex-end",
              gap: 0.75,
            }}
          >
            <Box sx={{ display: "flex", alignItems: "center", gap: 1.5 }}>
              {/* Saves the numbers currently on screen as the draft dashboard. */}
              <Button
                variant="contained"
                disabled={!isValidId || isGenerating}
                onClick={() => setConfirmOpen(true)}
                startIcon={
                  isGenerating ? (
                    <CircularProgress size={14} color="inherit" />
                  ) : undefined
                }
                sx={{
                  height: 40,
                  px: 2,
                  borderRadius: "6px",
                  bgcolor: "#1a64a8",
                  color: "#ffffff",
                  boxShadow: "none",
                  textTransform: "none",
                  fontSize: 13,
                  fontWeight: 500,
                  whiteSpace: "nowrap",
                  "&:hover": { bgcolor: "#155489", boxShadow: "none" },
                }}
              >
                {isGenerating
                  ? labels.draftDashboard.generating
                  : isFinal
                    ? labels.draftDashboard.generateFinal
                    : labels.draftDashboard.generate}
              </Button>

              {/* Only a generated final dashboard can be published, so the
                  button appears once there are saved numbers. */}
              {isFinal && dashboard?.generatedAt ? (
                <Button
                  variant="outlined"
                  disabled={!isValidId || isPublishing}
                  onClick={() => setLiveConfirmOpen(true)}
                  startIcon={
                    isPublishing ? (
                      <CircularProgress size={14} color="inherit" />
                    ) : undefined
                  }
                  sx={{
                    height: 40,
                    px: 2,
                    borderRadius: "6px",
                    borderColor: "#1a64a8",
                    color: "#1a64a8",
                    textTransform: "none",
                    fontSize: 13,
                    fontWeight: 500,
                    whiteSpace: "nowrap",
                    "&:hover": {
                      borderColor: "#155489",
                      bgcolor: theme.palette.action.hover,
                    },
                  }}
                >
                  {isPublishing
                    ? labels.draftDashboard.livePublishing
                    : labels.draftDashboard.live}
                </Button>
              ) : null}

              <ExportButton
                compact
                showMenu
                loading={exporting}
                disabled={!exportParts}
                onExport={(format) => {
                  if (!exportParts) return;
                  void runExport(format, exportParts.all, contentRef.current);
                }}
              >
                {labels.draftDashboard.export}
              </ExportButton>
            </Box>

            {/* When the numbers on screen were last saved. */}
            <Typography
              sx={{ fontSize: 12, color: theme.palette.text.secondary }}
            >
              {dashboard?.generatedAt
                ? `${labels.draftDashboard.lastUpdate}: ${formatDate(
                    dashboard.generatedAt,
                    language,
                    "dd MMMM yyyy, HH:mm",
                  )}`
                : labels.draftDashboard.notGeneratedYet}
            </Typography>
          </Box>
        </Box>

        {actionError ? <Alert severity="error">{actionError}</Alert> : null}

        {isLoading ? (
          <Box
            sx={{
              minHeight: 320,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
            }}
          >
            <CircularProgress size={32} />
          </Box>
        ) : pageError || !dashboard || !cards ? (
          <Alert severity="error">
            {pageError || labels.draftDashboard.loadError}
          </Alert>
        ) : (
          <Box
            ref={contentRef}
            sx={{ display: "flex", flexDirection: "column", gap: 3 }}
          >
            <DraftDashboardSummaryCards
              summary={mapCardsToSummary(cards)}
              labels={labels.draftDashboard.cards}
              formatNumber={toPageNumber}
            />

            <Box
              sx={{
                display: "flex",
                flexWrap: { xs: "wrap", md: "nowrap" },
                alignItems: "stretch",
                gap: 2.75,
              }}
            >
              <Box
                ref={overallRef}
                sx={{ flex: { xs: "1 1 100%", md: "0 0 486px" }, minWidth: 0 }}
              >
                <OverallStatusCard
                  title={labels.draftDashboard.charts.overallStatus}
                  centerLabel={statusLabels.totalIssues}
                  data={mapCardsToDonut(cards, statusLabels, language)}
                  counts={mapCardsToStatusCounts(cards, statusLabels, language)}
                  centerValue={toPageNumber(cards.totalIssues)}
                  onExport={(format) => {
                    if (!exportParts) return;
                    void runExport(
                      format,
                      exportParts.overall,
                      overallRef.current,
                      "status",
                    );
                  }}
                />
              </Box>
              <Box
                ref={agencyRef}
                sx={{ flex: { xs: "1 1 100%", md: "1 1 0" }, minWidth: 0 }}
              >
                <AgencyStatusCard
                  title={labels.draftDashboard.charts.primaryAgencies}
                  statusLabels={statusLabels}
                  formatNumber={toPageNumber}
                  rows={agencyRows}
                  onExport={(format) => {
                    if (!exportParts) return;
                    void runExport(
                      format,
                      exportParts.agencies,
                      agencyRef.current,
                      "agencies",
                    );
                  }}
                />
              </Box>
            </Box>

            <Box
              sx={{
                display: "flex",
                flexWrap: { xs: "wrap", md: "nowrap" },
                alignItems: "stretch",
                gap: 2.75,
              }}
            >
              <Box
                ref={workingGroupRef}
                sx={{ flex: { xs: "1 1 100%", md: "1 1 0" }, minWidth: 0 }}
              >
                <WorkingGroupStatusCard
                  title={labels.draftDashboard.charts.workingGroup}
                  statusLabels={statusLabels}
                  formatNumber={toPageNumber}
                  rows={workingGroupRows}
                  onExport={(format) => {
                    if (!exportParts) return;
                    void runExport(
                      format,
                      exportParts.workingGroups,
                      workingGroupRef.current,
                      "working-groups",
                    );
                  }}
                />
              </Box>
              <Box
                ref={categoryRef}
                sx={{ flex: { xs: "1 1 100%", md: "1 1 0" }, minWidth: 0 }}
              >
                <CategoryIssuesCard
                  title={labels.draftDashboard.charts.categoryOfIssues}
                  formatNumber={toPageNumber}
                  rows={categoryRows}
                  onExport={(format) => {
                    if (!exportParts) return;
                    void runExport(
                      format,
                      exportParts.categories,
                      categoryRef.current,
                      "categories",
                    );
                  }}
                />
              </Box>
            </Box>
          </Box>
        )}
      </Box>

      <AlertDialog
        open={confirmOpen}
        title={
          isFinal
            ? labels.draftDashboard.confirmFinalTitle
            : labels.draftDashboard.confirmTitle
        }
        description={
          isFinal
            ? labels.draftDashboard.confirmFinalDescription
            : labels.draftDashboard.confirmDescription
        }
        confirmLabel={labels.draftDashboard.confirm}
        cancelLabel={labels.draftDashboard.cancel}
        loading={isGenerating}
        onConfirm={() => void handleGenerate()}
        onCancel={() => setConfirmOpen(false)}
      />

      <AlertDialog
        open={liveConfirmOpen}
        title={labels.draftDashboard.confirmLiveTitle}
        description={labels.draftDashboard.confirmLiveDescription}
        confirmLabel={labels.draftDashboard.live}
        cancelLabel={labels.draftDashboard.cancel}
        loading={isPublishing}
        onConfirm={() => void handlePublishLive()}
        onCancel={() => setLiveConfirmOpen(false)}
      />

      <ToastNotification
        open={Boolean(toastMessage)}
        message={toastMessage}
        onClose={() => setToastMessage("")}
      />
    </DashboardPageContainer>
  );
}
