"use client";

import dayjs from "dayjs";
import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import StockIssueSearchPanel, {
  StockIssueSearchField,
} from "./StockIssueSearchPanel";
import { useCallback, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "@/components/SearchResults/index";
import { SessionWithTokens } from "@/config/authConfig";
import {
  batchSubmitExpiryItem,
  ExpiryItemResult,
  fetchExpiryItemList,
  submitExpiryItem,
} from "@/app/api/stockIssue/actions";
import { Box, Button } from "@mui/material";
import { useSession } from "next-auth/react";

type SearchQuery = {
  itemCode: string;
  itemName: string;
  expiryDate: string;
};
type SearchParamNames = keyof SearchQuery;

const ExpiryHandleTab: React.FC = () => {
  const BATCH_CHUNK_SIZE = 20;
  const { t } = useTranslation("stockIssue");
  const { data: session } = useSession() as { data: SessionWithTokens | null };
  const currentUserId = session?.id ? parseInt(session.id) : undefined;

  const [expiryItems, setExpiryItems] = useState<ExpiryItemResult[]>([]);
  const [submittingIds, setSubmittingIds] = useState<Set<number>>(new Set());
  const [batchSubmitting, setBatchSubmitting] = useState(false);
  const [batchProgress, setBatchProgress] = useState<{
    done: number;
    total: number;
  } | null>(null);
  const expirySubmitInFlightRef = useRef<Set<number>>(new Set());
  const batchSubmitInFlightRef = useRef(false);
  const [paging, setPaging] = useState({ pageNum: 1, pageSize: 10 });

  const searchFields: StockIssueSearchField<SearchParamNames>[] = useMemo(
    () => [
      { name: "itemCode", label: t("Item Code"), type: "text" },
      { name: "itemName", label: t("Item"), type: "text" },
      { name: "expiryDate", label: t("Expiry Date"), type: "date" },
    ],
    [t],
  );

  const handleSubmitSingle = useCallback(
    async (id: number) => {
      if (!currentUserId) {
        alert(t("User ID is required"));
        return;
      }
      const item = expiryItems.find((i) => i.id === id);
      if (!item) {
        alert(t("Item not found"));
        return;
      }
      if (expirySubmitInFlightRef.current.has(id)) return;

      try {
        expirySubmitInFlightRef.current.add(id);
        setSubmittingIds((prev) => new Set(prev).add(id));
        await submitExpiryItem(item.id, currentUserId);
        setExpiryItems((prev) => prev.filter((i) => i.id !== id));
      } catch (e) {
        console.error("submitExpiryItem failed:", e);
        const errMsg = e instanceof Error ? e.message : t("Unknown error");
        alert(`${t("Failed to submit expiry item")}: ${errMsg}`);
      } finally {
        expirySubmitInFlightRef.current.delete(id);
        setSubmittingIds((prev) => {
          const next = new Set(prev);
          next.delete(id);
          return next;
        });
      }
    },
    [currentUserId, t, expiryItems],
  );

  const handleSubmitAll = useCallback(async () => {
    if (!currentUserId) return;
    if (batchSubmitInFlightRef.current) return;
    const allIds = expiryItems.map((item) => item.id);
    if (allIds.length === 0) return;

    batchSubmitInFlightRef.current = true;
    setBatchSubmitting(true);
    setBatchProgress({ done: 0, total: allIds.length });
    try {
      for (let i = 0; i < allIds.length; i += BATCH_CHUNK_SIZE) {
        const chunkIds = allIds.slice(i, i + BATCH_CHUNK_SIZE);
        await batchSubmitExpiryItem(chunkIds, currentUserId);
        setExpiryItems((prev) => prev.filter((item) => !chunkIds.includes(item.id)));
        setBatchProgress({
          done: Math.min(i + chunkIds.length, allIds.length),
          total: allIds.length,
        });
      }
    } catch (error) {
      console.error("Failed to submit expiry items:", error);
      alert(
        `${t("Failed to submit")}: ${error instanceof Error ? error.message : "Unknown error"}`,
      );
    } finally {
      setBatchSubmitting(false);
      setBatchProgress(null);
      batchSubmitInFlightRef.current = false;
    }
  }, [currentUserId, expiryItems, t]);

  const expiryColumns = useMemo<Column<ExpiryItemResult>[]>(
    () => [
      { name: "itemCode", label: t("Item Code") },
      { name: "itemDescription", label: t("Item") },
      { name: "lotNo", label: t("Lot No.") },
      { name: "storeLocation", label: t("Location") },
      {
        name: "expiryDate",
        label: t("Expiry Date"),
        renderCell: (item) => {
          const raw = String(item.expiryDate ?? "").trim();
          if (!raw) return "—";
          let d;
          if (raw.includes(",")) {
            const parts = raw.split(",").map((s) => parseInt(s.trim(), 10));
            const [y, m, d_] = parts;
            if (
              parts.length >= 3 &&
              y != null &&
              m != null &&
              d_ != null &&
              !Number.isNaN(y) &&
              !Number.isNaN(m) &&
              !Number.isNaN(d_)
            ) {
              d = dayjs(new Date(y, m - 1, d_));
            } else {
              d = dayjs("");
            }
          } else {
            let normalized = raw;
            if (raw.length === 7) {
              normalized = raw.slice(0, 4) + "0" + raw.slice(4, 5) + raw.slice(5, 7);
            } else if (raw.length === 6) {
              normalized = raw.slice(0, 4) + "0" + raw.slice(4, 5) + "0" + raw.slice(5, 6);
            }
            d = dayjs(normalized, "YYYYMMDD", true);
          }
          return d.isValid() ? d.format(OUTPUT_DATE_FORMAT) : raw;
        },
      },
      { name: "remainingQty", label: t("Remaining Qty") },
      {
        name: "id",
        label: t("Action"),
        renderCell: (item) => (
          <Button
            size="small"
            variant="contained"
            color="primary"
            onClick={() => handleSubmitSingle(item.id)}
            disabled={submittingIds.has(item.id) || !currentUserId}
          >
            {submittingIds.has(item.id) ? t("Disposing...") : t("Disposed")}
          </Button>
        ),
      },
    ],
    [t, handleSubmitSingle, submittingIds, currentUserId],
  );

  const handleSearch = useCallback(
    async (query: Record<SearchParamNames, string>) => {
      setPaging((prev) => ({ ...prev, pageNum: 1 }));
      try {
        const result = await fetchExpiryItemList({
          itemCode: query.itemCode?.trim() || undefined,
          itemName: query.itemName?.trim() || undefined,
          expiryDate: query.expiryDate || undefined,
        });
        setExpiryItems(result);
      } catch (error) {
        console.error("Failed to search expiry items:", error);
        alert(t("Failed to load expiry items"));
      }
    },
    [t],
  );

  const pagedItems = useMemo(() => {
    const start = (paging.pageNum - 1) * paging.pageSize;
    return expiryItems.slice(start, start + paging.pageSize);
  }, [expiryItems, paging]);

  return (
    <Box>
      <StockIssueSearchPanel fields={searchFields} onSearch={handleSearch} />
      <Box sx={{ display: "flex", justifyContent: "flex-end", mb: 1 }}>
        <Button
          variant="contained"
          color="primary"
          onClick={handleSubmitAll}
          disabled={batchSubmitting || !currentUserId || expiryItems.length === 0}
        >
          {batchSubmitting
            ? `${t("Disposing...")} ${batchProgress ? `(${batchProgress.done}/${batchProgress.total})` : ""}`
            : t("Batch Disposed All")}
        </Button>
      </Box>
      <SearchResults<ExpiryItemResult>
        items={pagedItems}
        columns={expiryColumns}
        pagingController={paging}
        setPagingController={setPaging}
        totalCount={expiryItems.length}
      />
    </Box>
  );
};

export default ExpiryHandleTab;
