"use client";

import { useCallback, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import SearchBox, { Criterion } from "@/components/SearchBox";
import { ItemsResult, ItemsResultResponse } from "@/app/api/settings/item";
import { Box, Button, Card, CardContent, CircularProgress, Grid, Typography } from "@mui/material";
import Download from "@mui/icons-material/Download";
import Upload from "@mui/icons-material/Upload";
import { priceFormatter, OUTPUT_DATETIME_FORMAT } from "@/app/utils/formatUtil";
import dayjs, { Dayjs } from "dayjs";
import axiosInstance from "@/app/(main)/axios/axiosInstance";
import { NEXT_PUBLIC_API_URL } from "@/config/api";

type SearchQuery = {
  code: string;
  name: string;
};

type ItemPriceSearchComponent = React.FC & {
  Loading: React.FC;
};

type SearchParamNames = keyof SearchQuery;

const ItemPriceSearch: ItemPriceSearchComponent = () => {
  const { t } = useTranslation(["inventory", "common"]);

  const [item, setItem] = useState<ItemsResult | null>(null);
  const [isSearching, setIsSearching] = useState(false);
  const [isDownloading, setIsDownloading] = useState(false);
  const [isUploading, setIsUploading] = useState(false);

  const criteria: Criterion<SearchParamNames>[] = useMemo(
    () => [
      { label: t("Code"), paramName: "code", type: "text" },
      { label: t("Name"), paramName: "name", type: "text" },
    ],
    [t],
  );

  const fetchExactItem = useCallback(async (query: SearchQuery) => {
    const trimmedCode = query.code.trim();
    const trimmedName = query.name.trim();
    if (!trimmedCode && !trimmedName) {
      setItem(null);
      return;
    }

    setIsSearching(true);
    try {
      const params = {
        code: trimmedCode,
        name: trimmedName,
        pageNum: 1,
        pageSize: 20,
      };

      const res = await axiosInstance.get<ItemsResultResponse>(
        `${NEXT_PUBLIC_API_URL}/items/getRecordByPage`,
        { params },
      );

      if (!res?.data?.records || res.data.records.length === 0) {
        setItem(null);
        return;
      }

      const records = res.data.records as ItemsResult[];

      const exactMatch = records.find((r) => {
        const codeMatch = !trimmedCode || (r.code && String(r.code).toLowerCase() === trimmedCode.toLowerCase());
        const nameMatch = !trimmedName || (r.name && String(r.name).toLowerCase() === trimmedName.toLowerCase());
        return codeMatch && nameMatch;
      });

      setItem(exactMatch ?? null);
    } catch {
      setItem(null);
    } finally {
      setIsSearching(false);
    }
  }, []);

  const handleSearch = useCallback(
    (inputs: Record<SearchParamNames, string>) => {
      const query: SearchQuery = {
        code: inputs.code ?? "",
        name: inputs.name ?? "",
      };
      fetchExactItem(query);
    },
    [fetchExactItem],
  );

  const handleReset = useCallback(() => {
    setItem(null);
  }, []);

  const fileInputRef = useRef<HTMLInputElement>(null);

  const handleDownloadTemplate = useCallback(async () => {
    setIsDownloading(true);
    try {
      const res = await axiosInstance.get(
        `${NEXT_PUBLIC_API_URL}/items/marketUnitPrice/template`,
        { responseType: "blob" },
      );
      const url = URL.createObjectURL(res.data as Blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "market_unit_price_template.xlsx";
      a.click();
      URL.revokeObjectURL(url);
    } catch {
      alert(t("Download failed", { ns: "common" }));
    } finally {
      setIsDownloading(false);
    }
  }, [t]);

  const handleUploadClick = useCallback(() => {
    fileInputRef.current?.click();
  }, []);

  const handleUploadChange = useCallback(
    async (e: React.ChangeEvent<HTMLInputElement>) => {
      const file = e.target.files?.[0];
      if (!file) return;
      setIsUploading(true);
      const formData = new FormData();
      formData.append("file", file);
      try {
        const res = await axiosInstance.post<{
          success: boolean;
          updated?: number;
          errors?: string[];
        }>(
          `${NEXT_PUBLIC_API_URL}/items/marketUnitPrice/import`,
          formData,
          { headers: { "Content-Type": "multipart/form-data" } },
        );
        const data = res.data;
        if (!data.success) {
          const errMsg =
            data.errors?.length > 0
              ? `${t("Upload failed", { ns: "common" })}\n\n${data.errors.join("\n")}`
              : t("Upload failed", { ns: "common" });
          alert(errMsg);
          return;
        }
        const updated = data.updated ?? 0;
        if (data.errors?.length) {
          const successLabel = t("Upload successful", { ns: "common" });
          const countLabel = t("item(s) updated", { ns: "common" });
          const rowErrorsLabel = t("Upload row errors", { ns: "common" });
          const msg = `${successLabel} ${updated} ${countLabel}\n\n${rowErrorsLabel}\n${data.errors.join("\n")}`;
          alert(msg);
        } else {
          alert(t("Upload successful", { ns: "common" }));
        }
        if (item) fetchExactItem({ code: item.code ?? "", name: item.name ?? "" });
      } catch {
        alert(t("Upload failed", { ns: "common" }));
      } finally {
        setIsUploading(false);
        e.target.value = "";
      }
    },
    [item, fetchExactItem, t],
  );

  const avgPrice = useMemo(() => {
    if (item?.averageUnitPrice == null || item.averageUnitPrice === "") return null;
    const n = Number(item.averageUnitPrice);
    return Number.isFinite(n) ? n : null;
  }, [item?.averageUnitPrice]);

  return (
    <>
      <SearchBox<SearchParamNames>
        criteria={criteria}
        onSearch={handleSearch}
        onReset={handleReset}
        extraActions={
          <>
            <Button
              variant="outlined"
              startIcon={isDownloading ? <CircularProgress size={18} color="inherit" /> : <Download />}
              onClick={handleDownloadTemplate}
              disabled={isDownloading || isUploading}
              sx={{ borderColor: "#e2e8f0", color: "#334155" }}
            >
              {isDownloading ? t("Downloading...", { ns: "common" }) : t("Download Template", { ns: "common" })}
            </Button>
            <Button
              variant="outlined"
              component="label"
              startIcon={isUploading ? <CircularProgress size={18} color="inherit" /> : <Upload />}
              disabled={isDownloading || isUploading}
              sx={{ borderColor: "#e2e8f0", color: "#334155" }}
            >
              {isUploading ? t("Uploading...", { ns: "common" }) : t("Upload", { ns: "common" })}
              <input
                ref={fileInputRef}
                type="file"
                hidden
                accept=".xlsx,.xls"
                onChange={handleUploadChange}
              />
            </Button>
          </>
        }
      />

      <Box sx={{ mt: 2 }}>
        {isSearching && (
          <Typography variant="body2" color="text.secondary">
            {t("Searching")}...
          </Typography>
        )}

        {!isSearching && !item && (
          <Typography variant="body2" color="text.secondary">
            {t("No item selected")}
          </Typography>
        )}

        {!isSearching && item && (
          <Grid container spacing={2} sx={{ alignItems: "stretch" }}>
            {/* Box 1: Item info */}
            <Grid item xs={12} sm={6} md={4} sx={{ display: "flex" }}>
              <Card
                variant="outlined"
                sx={{
                  borderRadius: 2,
                  flex: 1,
                  display: "flex",
                  flexDirection: "column",
                }}
              >
                <CardContent sx={{ py: 2, flex: 1, "&:last-child": { pb: 2 } }}>
                  <Typography variant="h6" sx={{ fontWeight: 600, mb: 1 }}>
                    {item.code}
                  </Typography>
                  <Typography
                    variant="body1"
                    color="text.secondary"
                    sx={{
                      mb: 0.5,
                      height: "2.5em",
                      lineHeight: 1.25,
                      display: "-webkit-box",
                      WebkitLineClamp: 2,
                      WebkitBoxOrient: "vertical",
                      overflow: "hidden",
                    }}
                  >
                    {item.name}
                  </Typography>
                  <Typography variant="body2" color="text.secondary">
                    {[
                      item.type ? t(item.type.toUpperCase(), { ns: "common" }) : null,
                      item.purchaseUnit ?? null,
                    ]
                      .filter(Boolean)
                      .join(" · ") || "—"}
                  </Typography>
                </CardContent>
              </Card>
            </Grid>

            {/* Box 2: Avg unit price (from items table) */}
            <Grid item xs={12} sm={6} md={4} sx={{ display: "flex" }}>
              <Card variant="outlined" sx={{ borderRadius: 2, flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
                <CardContent sx={{ py: 2, flex: 1, minHeight: 0, "&:last-child": { pb: 2 }, display: "flex", flexDirection: "column", alignItems: "flex-start", justifyContent: "flex-start" }}>
                  <Typography variant="subtitle2" color="text.secondary" sx={{ mb: 1, flexShrink: 0 }}>
                    {t("Average unit price", { ns: "inventory" })}
                  </Typography>
                  <Typography variant="h5" sx={{ width: "100%", flex: 1, display: "flex", alignItems: "center", justifyContent: "center", textAlign: "center", fontWeight: 500, color: "black", minHeight: 0 }}>
                    {avgPrice != null && avgPrice !== 0
                      ? `HKD ${priceFormatter.format(avgPrice)}`
                      : t("No Purchase Order After 2026-01-01", { ns: "common" })}
                  </Typography>
                  <Box sx={{ mt: "auto", height: 32, display: "flex", alignItems: "center" }} aria-hidden />
                </CardContent>
              </Card>
            </Grid>

            {/* Box 3: Latest market unit price & update date (from items table) */}
            <Grid item xs={12} sm={6} md={4} sx={{ display: "flex" }}>
              <Card variant="outlined" sx={{ borderRadius: 2, flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
                <CardContent sx={{ py: 2, flex: 1, minHeight: 0, "&:last-child": { pb: 2 }, display: "flex", flexDirection: "column", alignItems: "flex-start", justifyContent: "flex-start" }}>
                  <Typography variant="subtitle2" color="text.secondary" sx={{ mb: 1, flexShrink: 0 }}>
                    {t("Latest market unit price", { ns: "inventory" })}
                  </Typography>
                  <Typography variant="h5" sx={{ width: "100%", textAlign: "center", fontWeight: 500, color: "black", flex: 1, minHeight: 0, display: "flex", alignItems: "center", justifyContent: "center" }}>
                    {item.latestMarketUnitPrice != null && Number(item.latestMarketUnitPrice) !== 0
                      ? `HKD ${priceFormatter.format(Number(item.latestMarketUnitPrice))}`
                      : t("No Import Record", { ns: "common" })}
                  </Typography>
                  <Box sx={{ mt: "auto", height: 32, display: "flex", alignItems: "center" }}>
                    <Typography variant="body2" color="text.secondary">
                      {item.latestMupUpdatedDate != null && item.latestMupUpdatedDate !== ""
                        ? (() => {
                            const raw = item.latestMupUpdatedDate;
                            let d: Dayjs | null = null;
                            if (Array.isArray(raw) && raw.length >= 5) {
                              const [y, m, day, h, min] = raw as number[];
                              d = dayjs(new Date(y, (m ?? 1) - 1, day ?? 1, h ?? 0, min ?? 0));
                            } else if (typeof raw === "string") {
                              d = dayjs(raw);
                            }
                            return d?.isValid() ? d.format(OUTPUT_DATETIME_FORMAT) : String(raw);
                          })()
                        : item.latestMarketUnitPrice != null && Number(item.latestMarketUnitPrice) !== 0
                          ? "—"
                          : ""}
                    </Typography>
                  </Box>
                </CardContent>
              </Card>
            </Grid>
          </Grid>
        )}
      </Box>
    </>
  );
};

ItemPriceSearch.Loading = function Loading() {
  return <div>Loading...</div>;
};

export default ItemPriceSearch;
