"use client";

import React, { useMemo, useState, useCallback, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { BomWeightingScoreResult } from "@/app/api/settings/bomWeighting";
import { updateBomWeightingScoreClient } from "@/app/api/settings/bomWeighting/client";
import { recalcBomScoresClient } from "@/app/api/bom/recalculateClient";
import { GridColDef, GridValueFormatterParams } from "@mui/x-data-grid";
import StyledDataGrid from "../StyledDataGrid";
import Paper from "@mui/material/Paper";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import { successDialog, warningDialog } from "../Swal/CustomAlerts";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";

interface Props {
  bomWeightingScores: BomWeightingScoreResult[];
  onWeightingUpdated?: () => void;
}

const BomWeightingScoreTable: React.FC<Props> & { Loading?: React.FC } = ({ bomWeightingScores: initialBomWeightingScores, onWeightingUpdated }) => {
  const { t } = useTranslation(["bomWeighting", "common"]);
  const [bomWeightingScores, setBomWeightingScores] = useState(initialBomWeightingScores);
  const [isEditMode, setIsEditMode] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [draftWeightingById, setDraftWeightingById] = useState<Record<number, string>>({});

  useEffect(() => {
    setBomWeightingScores(initialBomWeightingScores);
  }, [initialBomWeightingScores]);

  const extractWeightingNumber = useCallback((row: BomWeightingScoreResult): number => {
    const w = row.weighting;
    if (w == null) return 0;
    if (typeof w === "number") return w;
    if (typeof w === "string") return parseFloat(w) || 0;
    if (typeof w === "object" && w !== null) {
      const obj = w as any;
      if (typeof obj.value === "number") return obj.value;
      if (typeof obj.toString === "function") return parseFloat(obj.toString()) || 0;
    }
    return parseFloat(String(w)) || 0;
  }, []);

  const enterEditMode = useCallback(() => {
    const nextDraft: Record<number, string> = {};
    for (const row of bomWeightingScores) {
      nextDraft[row.id] = String(extractWeightingNumber(row));
    }
    setDraftWeightingById(nextDraft);
    setIsEditMode(true);
  }, [bomWeightingScores, extractWeightingNumber]);

  const cancelEditMode = useCallback(() => {
    setIsEditMode(false);
    setDraftWeightingById({});
  }, []);

  const handleSave = useCallback(async (e?: React.MouseEvent) => {
    e?.preventDefault();
    e?.stopPropagation();
    
    if (!isEditMode || isSaving) return;

    try {
      let sum = 0;
      for (const row of bomWeightingScores) {
        const raw = draftWeightingById[row.id] ?? String(extractWeightingNumber(row));
        const n = parseFloat(raw);
        if (Number.isNaN(n)) {
          await warningDialog("權重必須為數字", t);
          return;
        }
        sum += n;
      }

      const EPS = 1e-6;
      if (Math.abs(sum - 1) > EPS) {
        await warningDialog(`權重總和必須等於 1（目前總和: ${sum.toFixed(4)}）`, t);
        return;
      }

      setIsSaving(true);
      const updates = bomWeightingScores
        .map((row) => {
          const nextWeightingStr = draftWeightingById[row.id];
          if (nextWeightingStr == null) return null;

          const prevWeighting = extractWeightingNumber(row);
          const nextWeighting = parseFloat(nextWeightingStr);
          if (Number.isNaN(nextWeighting)) return null;

          // Only update changed values (weighting only; range locked)
          if (nextWeighting === prevWeighting) return null;

          return {
            row,
            nextWeighting,
          };
        })
        .filter(Boolean) as Array<{ row: BomWeightingScoreResult; nextWeighting: number }>;

      let updatedCount: number | null = null;

      if (updates.length > 0) {
        const updatedRows = await Promise.all(
          updates.map(({ row, nextWeighting }) =>
            updateBomWeightingScoreClient({
              id: row.id,
              name: row.name,
              range: row.range,
              weighting: nextWeighting,
              remarks: row.remarks || undefined,
            }),
          ),
        );

        const updatedById = new Map(updatedRows.map((r) => [r.id, r]));
        setBomWeightingScores((prev) =>
          prev.map((r) => updatedById.get(r.id) ?? r),
        );

        // Wait a bit to ensure all weighting updates are committed to database
        // before recalculating base scores
        console.log("Waiting for weighting updates to commit...");
        await new Promise(resolve => setTimeout(resolve, 200));

        // After weighting changes, trigger BOM baseScore recalculation on the server
        try {
          console.log("Triggering BOM base score recalculation...");
          const result = await recalcBomScoresClient();
          updatedCount = result?.updatedCount ?? null;
          console.log(`BOM base scores recalculated: ${updatedCount} BOMs updated`);
          
          // Wait a bit more to ensure recalculation transaction is committed
          // before refreshing the frontend
          await new Promise(resolve => setTimeout(resolve, 300));
          
          // Notify parent component to refresh BOM scores if needed
          if (onWeightingUpdated) {
            console.log("Refreshing BOM scores in frontend...");
            await onWeightingUpdated();
            console.log("BOM scores refreshed");
          }
        } catch (recalcError) {
          console.error("Failed to recalculate BOM base scores:", recalcError);
          // We don't block the main save flow if recalculation fails
        }
      }

      cancelEditMode();

      // Show success message, with extra info about how many BOM base scores were recalculated (if available)
      if (updatedCount != null) {
        await successDialog(
          `${t("Update Success")}（已重新計算 ${updatedCount} 筆 BOM 基礎分）`,
          t,
        );
      } else {
        await successDialog(t("Update Success"), t);
      }
    } catch (error: any) {
      console.error("Error updating bom weighting score:", error);
      const errorMessage = error?.response?.data?.message || error?.message || t("Update Failed") || "Update failed. Please try again.";
      alert(errorMessage);
    } finally {
      setIsSaving(false);
    }
  }, [isEditMode, isSaving, bomWeightingScores, draftWeightingById, extractWeightingNumber, cancelEditMode, t]);

  const columns = useMemo<GridColDef<BomWeightingScoreResult>[]>(
    () => [
      {
        field: "name",
        headerName: t("Scoring Item"),
        flex: 1,
      },
      {
        field: "range",
        headerName: t("Range"),
        flex: 1,
        align: "left",
        headerAlign: "left",
      },
      {
        field: "weighting",
        headerName: t("Weighting"),
        flex: 1,
        sortable: false,
        valueFormatter: (params: GridValueFormatterParams) => {
          const value = params.value;
          if (value == null || value === undefined) return "";
          return typeof value === "number" ? value.toFixed(2) : "";
        },
        renderCell: (params) => {
          if (!isEditMode) {
            const value = extractWeightingNumber(params.row);
            return value.toFixed(2);
          }

          const current = draftWeightingById[params.row.id] ?? String(extractWeightingNumber(params.row));
          return (
            <TextField
              size="small"
              type="number"
              inputProps={{ step: "0.01" }}
              value={current}
              onClick={(e) => e.stopPropagation()}
              onChange={(e) => {
                const next = e.target.value;
                setDraftWeightingById((prev) => ({ ...prev, [params.row.id]: next }));
              }}
              sx={{ width: "100%" }}
            />
          );
        },
      },
    ],
    [t, isEditMode, draftWeightingById, extractWeightingNumber],
  );

  return (
    <>
      <Paper variant="outlined" sx={{ overflow: "hidden" }}>
        <Box sx={{ p: 2, pb: 0 }}>
          <Stack direction="row" justifyContent="flex-end" spacing={1}>
            {isEditMode ? (
              <>
                <Button variant="outlined" onClick={cancelEditMode} disabled={isSaving}>
                  {t("Cancel")}
                </Button>
                <Button variant="contained" onClick={handleSave} disabled={isSaving}>
                  {isSaving ? t("Saving") || "Saving..." : t("Save")}
                </Button>
              </>
            ) : (
              <Button variant="contained" onClick={enterEditMode}>
                {t("Edit")}
              </Button>
            )}
          </Stack>
        </Box>
        <StyledDataGrid
          rows={bomWeightingScores}
          columns={columns}
          getRowId={(row) => row.id}
          autoHeight
          disableRowSelectionOnClick
          hideFooterPagination={true}
          sx={{
            "& .MuiDataGrid-columnHeaderTitle": { fontSize: 15 },
            "& .MuiDataGrid-cell": { fontSize: 16 },
          }}
        />
      </Paper>
    </>
  );
};

BomWeightingScoreTable.Loading = () => {
  return (
    <Paper variant="outlined" sx={{ overflow: "hidden", minHeight: 400 }}>
      <div style={{ padding: "16px" }}>Loading...</div>
    </Paper>
  );
};

export default BomWeightingScoreTable;
