"use client";

import React, { useState, useEffect, useMemo } from "react";
import Search from "@mui/icons-material/Search";
import Visibility from "@mui/icons-material/Visibility";
import FormatListNumbered from "@mui/icons-material/FormatListNumbered";
import ShowChart from "@mui/icons-material/ShowChart";
import Download from "@mui/icons-material/Download";
import Hub from "@mui/icons-material/Hub";
import Settings from "@mui/icons-material/Settings";
import Clear from "@mui/icons-material/Clear";
import { CircularProgress } from "@mui/material";
import PageTitleBar from "@/components/PageTitleBar";
import dayjs from "dayjs";
import { NEXT_PUBLIC_API_URL } from "@/config/api";
import { clientAuthFetch } from "@/app/utils/clientAuthFetch";

type ItemDailyOutRow = {
  itemCode: string;
  itemName: string;
  unit?: string;
  onHandQty?: number | null;
  fakeOnHandQty?: number | null;
  avgQtyLastMonth?: number;
  dailyQty?: number | null;
  isCoffee?: number;
  isTea?: number;
  isLemon?: number;
};

export default function ProductionSchedulePage() {
  const [searchDate, setSearchDate] = useState(dayjs().format("YYYY-MM-DD"));
  const [schedules, setSchedules] = useState<any[]>([]);
  const [selectedLines, setSelectedLines] = useState<any[]>([]);
  const [isDetailOpen, setIsDetailOpen] = useState(false);
  const [selectedPs, setSelectedPs] = useState<any>(null);
  const [loading, setLoading] = useState(false);
  const [isGenerating, setIsGenerating] = useState(false);

  const [isForecastDialogOpen, setIsForecastDialogOpen] = useState(false);
  const [forecastStartDate, setForecastStartDate] = useState(
    dayjs().format("YYYY-MM-DD")
  );
  const [forecastDays, setForecastDays] = useState<number | "">(7);

  const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);
  const [exportFromDate, setExportFromDate] = useState(
    dayjs().format("YYYY-MM-DD")
  );

  const [isDailyOutPanelOpen, setIsDailyOutPanelOpen] = useState(false);
  const [itemDailyOutList, setItemDailyOutList] = useState<ItemDailyOutRow[]>([]);
  const [itemDailyOutLoading, setItemDailyOutLoading] = useState(false);
  const [dailyOutSavingCode, setDailyOutSavingCode] = useState<string | null>(null);
  const [dailyOutClearingCode, setDailyOutClearingCode] = useState<string | null>(null);
  const [coffeeOrTeaUpdating, setCoffeeOrTeaUpdating] = useState<string | null>(null);
  const [fakeOnHandSavingCode, setFakeOnHandSavingCode] = useState<string | null>(null);
  const [fakeOnHandClearingCode, setFakeOnHandClearingCode] = useState<string | null>(null);

  useEffect(() => {
    handleSearch();
  }, []);

  const formatBackendDate = (dateVal: any) => {
    if (Array.isArray(dateVal)) {
      const [year, month, day] = dateVal;
      return dayjs(new Date(year, month - 1, day)).format("DD MMM (dddd)");
    }
    return dayjs(dateVal).format("DD MMM (dddd)");
  };

  const formatNum = (num: any) => {
    return new Intl.NumberFormat("en-US").format(Number(num) || 0);
  };

  const handleSearch = async () => {
    setLoading(true);
    try {
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/ps/search-ps?produceAt=${searchDate}`,
        { method: "GET" }
      );
      if (response.status === 401 || response.status === 403) return;
      const data = await response.json();
      setSchedules(Array.isArray(data) ? data : []);
    } catch (e) {
      console.error("Search Error:", e);
    } finally {
      setLoading(false);
    }
  };

  const handleConfirmForecast = async () => {
    if (!forecastStartDate || forecastDays === "" || forecastDays < 1) {
      alert("Please enter a valid start date and number of days (≥1).");
      return;
    }
    setLoading(true);
    setIsForecastDialogOpen(false);
    try {
      const params = new URLSearchParams({
        startDate: forecastStartDate,
        days: forecastDays.toString(),
      });
      const url = `${NEXT_PUBLIC_API_URL}/productionSchedule/testDetailedSchedule?${params.toString()}`;
      const response = await clientAuthFetch(url, { method: "GET" });
      if (response.status === 401 || response.status === 403) return;
      if (response.ok) {
        await handleSearch();
        alert("成功計算排期!");
      } else {
        const errorText = await response.text();
        console.error("Forecast failed:", errorText);
        alert(`計算錯誤: ${response.status} - ${errorText.substring(0, 120)}`);
      }
    } catch (e) {
      console.error("Forecast Error:", e);
      alert("發生不明狀況.");
    } finally {
      setLoading(false);
    }
  };

  const handleConfirmExport = async () => {
    if (!exportFromDate) {
      alert("Please select a from date.");
      return;
    }
    setLoading(true);
    setIsExportDialogOpen(false);
    try {
      const params = new URLSearchParams({ fromDate: exportFromDate });
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/productionSchedule/export-prod-schedule?${params.toString()}`,
        { method: "GET" }
      );
      if (response.status === 401 || response.status === 403) return;
      if (!response.ok) throw new Error(`Export failed: ${response.status}`);
      const blob = await response.blob();
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `production_schedule_from_${exportFromDate.replace(/-/g, "")}.xlsx`;
      document.body.appendChild(a);
      a.click();
      window.URL.revokeObjectURL(url);
      document.body.removeChild(a);
    } catch (e) {
      console.error("Export Error:", e);
      alert("Failed to export file.");
    } finally {
      setLoading(false);
    }
  };

  const handleViewDetail = async (ps: any) => {
    if (!ps?.id) {
      alert("Cannot open details: missing schedule ID");
      return;
    }
    setSelectedPs(ps);
    setLoading(true);
    try {
      const url = `${NEXT_PUBLIC_API_URL}/ps/search-ps-line?psId=${ps.id}`;
      const response = await clientAuthFetch(url, { method: "GET" });
      if (response.status === 401 || response.status === 403) return;
      if (!response.ok) {
        const errorText = await response.text().catch(() => "(no text)");
        alert(`Server error ${response.status}: ${errorText}`);
        return;
      }
      const data = await response.json();
      setSelectedLines(Array.isArray(data) ? data : []);
      setIsDetailOpen(true);
    } catch (err) {
      console.error("Fetch failed:", err);
      alert("Network or fetch error – check console");
    } finally {
      setLoading(false);
    }
  };

  const handleAutoGenJob = async () => {
    setIsGenerating(true);
    try {
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/productionSchedule/detail/detailed/release`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ id: selectedPs.id }),
        }
      );
      if (response.status === 401 || response.status === 403) return;
      if (response.ok) {
        const data = await response.json();
        alert(data.message || "Operation completed.");
        setIsDetailOpen(false);
      } else {
        alert("Failed to generate jobs.");
      }
    } catch (e) {
      console.error("Release Error:", e);
    } finally {
      setIsGenerating(false);
    }
  };

  const fromDateDefault = dayjs().subtract(29, "day").format("YYYY-MM-DD");
  const toDateDefault = dayjs().format("YYYY-MM-DD");

  const fetchItemDailyOut = async () => {
    setItemDailyOutLoading(true);
    try {
      const params = new URLSearchParams({
        fromDate: fromDateDefault,
        toDate: toDateDefault,
      });
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/ps/itemDailyOut.json?${params.toString()}`,
        { method: "GET" }
      );
      if (response.status === 401 || response.status === 403) return;
      const data = await response.json();
      const rows: ItemDailyOutRow[] = (Array.isArray(data) ? data : []).map(
        (r: any) => ({
          itemCode: r.itemCode ?? "",
          itemName: r.itemName ?? "",
          unit: r.unit != null ? String(r.unit) : "",
          onHandQty: r.onHandQty != null ? Number(r.onHandQty) : null,
          fakeOnHandQty:
            r.fakeOnHandQty != null && r.fakeOnHandQty !== ""
              ? Number(r.fakeOnHandQty)
              : null,
          avgQtyLastMonth:
            r.avgQtyLastMonth != null ? Number(r.avgQtyLastMonth) : undefined,
          dailyQty:
            r.dailyQty != null && r.dailyQty !== ""
              ? Number(r.dailyQty)
              : null,
          isCoffee: r.isCoffee != null ? Number(r.isCoffee) : 0,
          isTea: r.isTea != null ? Number(r.isTea) : 0,
          isLemon: r.isLemon != null ? Number(r.isLemon) : 0,
        })
      );
      setItemDailyOutList(rows);
    } catch (e) {
      console.error("itemDailyOut Error:", e);
      setItemDailyOutList([]);
    } finally {
      setItemDailyOutLoading(false);
    }
  };

  const openSettingsPanel = () => {
    setIsDailyOutPanelOpen(true);
    fetchItemDailyOut();
  };

  const handleSaveDailyQty = async (itemCode: string, dailyQty: number) => {
    setDailyOutSavingCode(itemCode);
    try {
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/ps/setDailyQtyOut`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ itemCode, dailyQty }),
        }
      );
      if (response.status === 401 || response.status === 403) return;
      if (response.ok) {
        setItemDailyOutList((prev) =>
          prev.map((r) =>
            r.itemCode === itemCode ? { ...r, dailyQty } : r
          )
        );
      } else {
        alert("儲存失敗");
      }
    } catch (e) {
      console.error("setDailyQtyOut Error:", e);
      alert("儲存失敗");
    } finally {
      setDailyOutSavingCode(null);
    }
  };

  const handleClearDailyQty = async (itemCode: string) => {
    if (!confirm(`確定要清除${itemCode}的設定排期每天出貨量嗎？`)) return;
    setDailyOutClearingCode(itemCode);
    try {
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/ps/clearDailyQtyOut`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ itemCode }),
        }
      );
      if (response.status === 401 || response.status === 403) return;
      if (response.ok) {
        setItemDailyOutList((prev) =>
          prev.map((r) =>
            r.itemCode === itemCode ? { ...r, dailyQty: null } : r
          )
        );
      } else {
        alert("清除失敗");
      }
    } catch (e) {
      console.error("clearDailyQtyOut Error:", e);
      alert("清除失敗");
    } finally {
      setDailyOutClearingCode(null);
    }
  };

  const handleSetCoffeeOrTea = async (
    itemCode: string,
    systemType: "coffee" | "tea" | "lemon",
    enabled: boolean
  ) => {
    const key = `${itemCode}-${systemType}`;
    setCoffeeOrTeaUpdating(key);
    try {
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/ps/setCoffeeOrTea`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ itemCode, systemType, enabled }),
        }
      );
      if (response.status === 401 || response.status === 403) return;
      if (response.ok) {
        setItemDailyOutList((prev) =>
          prev.map((r) => {
            if (r.itemCode !== itemCode) return r;
            const next = { ...r };
            if (systemType === "coffee") next.isCoffee = enabled ? 1 : 0;
            if (systemType === "tea") next.isTea = enabled ? 1 : 0;
            if (systemType === "lemon") next.isLemon = enabled ? 1 : 0;
            return next;
          })
        );
      } else {
        alert("設定失敗");
      }
    } catch (e) {
      console.error("setCoffeeOrTea Error:", e);
      alert("設定失敗");
    } finally {
      setCoffeeOrTeaUpdating(null);
    }
  };

  const handleSetFakeOnHand = async (itemCode: string, onHandQty: number) => {
    setFakeOnHandSavingCode(itemCode);
    try {
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/ps/setFakeOnHand`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ itemCode, onHandQty }),
        }
      );
      if (response.status === 401 || response.status === 403) return;
      if (response.ok) {
        setItemDailyOutList((prev) =>
          prev.map((r) =>
            r.itemCode === itemCode ? { ...r, fakeOnHandQty: onHandQty } : r
          )
        );
      } else {
        alert("設定失敗");
      }
    } catch (e) {
      console.error("setFakeOnHand Error:", e);
      alert("設定失敗");
    } finally {
      setFakeOnHandSavingCode(null);
    }
  };

  const handleClearFakeOnHand = async (itemCode: string) => {
    if (!confirm("確定要清除此物料的設定排期庫存嗎？")) return;
    setFakeOnHandClearingCode(itemCode);
    try {
      const response = await clientAuthFetch(
        `${NEXT_PUBLIC_API_URL}/ps/setFakeOnHand`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ itemCode, onHandQty: null }),
        }
      );
      if (response.status === 401 || response.status === 403) return;
      if (response.ok) {
        setItemDailyOutList((prev) =>
          prev.map((r) =>
            r.itemCode === itemCode ? { ...r, fakeOnHandQty: null } : r
          )
        );
      } else {
        alert("清除失敗");
      }
    } catch (e) {
      console.error("clearFakeOnHand Error:", e);
      alert("清除失敗");
    } finally {
      setFakeOnHandClearingCode(null);
    }
  };

  return (
    <div className="space-y-4">
      <PageTitleBar
        title="排程"
        actions={
          <>
            <button
              type="button"
              onClick={openSettingsPanel}
              className="inline-flex items-center gap-2 rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-700 shadow-sm transition hover:bg-slate-50 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700"
            >
              <Settings sx={{ fontSize: 16 }} />
              排期設定
            </button>
            <button
              type="button"
              onClick={() => setIsExportDialogOpen(true)}
              className="inline-flex items-center gap-2 rounded-lg border border-emerald-500/70 bg-white px-4 py-2 text-sm font-semibold text-emerald-600 shadow-sm transition hover:bg-emerald-50 dark:border-emerald-500/50 dark:bg-slate-800 dark:text-emerald-400 dark:hover:bg-emerald-500/10"
            >
              <Download sx={{ fontSize: 16 }} />
              匯出計劃/物料需求Excel
            </button>
            <button
              type="button"
              onClick={() => setIsForecastDialogOpen(true)}
              disabled={loading}
              className="inline-flex items-center gap-2 rounded-lg bg-blue-500 px-4 py-2 text-sm font-semibold text-white shadow-sm transition hover:bg-blue-600 disabled:opacity-50"
            >
              {loading ? (
                <CircularProgress size={16} sx={{ display: "block" }} />
              ) : (
                <ShowChart sx={{ fontSize: 16 }} />
              )}
              預測排期
            </button>
          </>
        }
        className="mb-4"
      />

      {/* Query Bar */}
      <div className="app-search-criteria mb-4 flex flex-wrap items-center gap-2 p-4">
        <label className="sr-only" htmlFor="ps-search-date">
          生產日期
        </label>
        <input
          id="ps-search-date"
          type="date"
          value={searchDate}
          onChange={(e) => setSearchDate(e.target.value)}
          className="rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 placeholder-slate-400 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-100"
        />
        <button
          type="button"
          onClick={handleSearch}
          className="inline-flex items-center gap-2 rounded-lg bg-blue-500 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-blue-600"
        >
          <Search sx={{ fontSize: 16 }} />
          搜尋
        </button>
      </div>

      {/* Main Table */}
      <div className="overflow-hidden rounded-lg border border-slate-200 bg-white shadow-sm dark:border-slate-700 dark:bg-slate-800">
        <div className="overflow-x-auto">
          <table className="w-full min-w-[320px] text-left text-sm">
            <thead className="sticky top-0 bg-slate-50 dark:bg-slate-700">
              <tr>
                <th className="w-[100px] px-4 py-3 text-center font-bold text-slate-700 dark:text-slate-200">
                  詳細
                </th>
                <th className="px-4 py-3 font-bold text-slate-700 dark:text-slate-200">
                  生產日期
                </th>
                <th className="px-4 py-3 text-right font-bold text-slate-700 dark:text-slate-200">
                  預計生產數
                </th>
                <th className="px-4 py-3 text-right font-bold text-slate-700 dark:text-slate-200">
                  成品款數
                </th>
              </tr>
            </thead>
            <tbody>
              {schedules.map((ps) => (
                <tr
                  key={ps.id}
                  className="border-t border-slate-200 text-slate-700 transition hover:bg-slate-50 dark:border-slate-700 dark:text-slate-300 dark:hover:bg-slate-700/50"
                >
                  <td className="px-4 py-3 text-center">
                    <button
                      type="button"
                      onClick={() => handleViewDetail(ps)}
                      className="rounded p-1 text-blue-500 hover:bg-blue-50 hover:text-blue-600 dark:text-blue-400 dark:hover:bg-blue-500/20"
                    >
                      <Visibility sx={{ fontSize: 16 }} />
                    </button>
                  </td>
                  <td className="px-4 py-3">
                    {formatBackendDate(ps.produceAt)}
                  </td>
                  <td className="px-4 py-3 text-right">
                    {formatNum(ps.totalEstProdCount)}
                  </td>
                  <td className="px-4 py-3 text-right">
                    {formatNum(ps.totalFGType)}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      {/* Detail Modal – z-index above sidebar drawer (1200) so they don't overlap on small windows */}
      {isDetailOpen && (
        <div
          className="fixed inset-0 z-[1300] flex items-center justify-center p-4"
          role="dialog"
          aria-modal="true"
          aria-labelledby="detail-title"
        >
          <div
            className="absolute inset-0 bg-black/50"
            onClick={() => !isGenerating && setIsDetailOpen(false)}
          />
          <div className="relative z-10 flex max-h-[90vh] w-full max-w-4xl flex-col overflow-hidden rounded-lg border border-slate-200 bg-white shadow-xl dark:border-slate-700 dark:bg-slate-800">
            <div className="flex items-center gap-2 border-b border-slate-200 bg-blue-500 px-4 py-3 text-white dark:border-slate-700">
              <FormatListNumbered sx={{ fontSize: 20, flexShrink: 0 }} />
              <h2 id="detail-title" className="text-lg font-semibold">
                排期詳細: {selectedPs?.id} (
                {formatBackendDate(selectedPs?.produceAt)})
              </h2>
            </div>
            <div className="max-h-[65vh] overflow-auto">
              <table className="w-full text-left text-sm">
                <thead className="sticky top-0 bg-slate-50 dark:bg-slate-700">
                  <tr>
                    <th className="px-4 py-2 font-bold text-slate-700 dark:text-slate-200">
                      工單號
                    </th>
                    <th className="px-4 py-2 font-bold text-slate-700 dark:text-slate-200">
                      物料編號
                    </th>
                    <th className="px-4 py-2 font-bold text-slate-700 dark:text-slate-200">
                      物料名稱
                    </th>
                    <th className="px-4 py-2 text-right font-bold text-slate-700 dark:text-slate-200">
                      每日平均出貨量
                    </th>
                    <th className="px-4 py-2 text-right font-bold text-slate-700 dark:text-slate-200">
                      出貨前預計存貨量
                    </th>
                    <th className="px-4 py-2 font-bold text-slate-700 dark:text-slate-200">
                      單位
                    </th>
                    <th className="px-4 py-2 text-right font-bold text-slate-700 dark:text-slate-200">
                      可用日
                    </th>
                    <th className="px-4 py-2 text-right font-bold text-slate-700 dark:text-slate-200">
                      生產量(批)
                    </th>
                    <th className="px-4 py-2 text-right font-bold text-slate-700 dark:text-slate-200">
                      預計生產包數
                    </th>
                    <th className="px-4 py-2 text-center font-bold text-slate-700 dark:text-slate-200">
                      優先度
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {selectedLines.map((line: any) => (
                    <tr
                      key={line.id}
                      className="border-t border-slate-200 text-slate-700 hover:bg-slate-50 dark:border-slate-700 dark:text-slate-300 dark:hover:bg-slate-700/30"
                    >
                      <td className="px-4 py-2 font-semibold text-blue-600 dark:text-blue-400">
                        {line.joCode || "-"}
                      </td>
                      <td className="px-4 py-2 font-semibold">
                        {line.itemCode}
                      </td>
                      <td className="px-4 py-2">{line.itemName}</td>
                      <td className="px-4 py-2 text-right">
                        {formatNum(line.avgQtyLastMonth)}
                      </td>
                      <td className="px-4 py-2 text-right">
                        {formatNum(line.stockQty)}
                      </td>
                      <td className="px-4 py-2">{line.stockUnit}</td>
                      <td
                        className={`px-4 py-2 text-right ${
                          line.daysLeft < 5
                            ? "font-bold text-red-600 dark:text-red-400"
                            : ""
                        }`}
                      >
                        {line.daysLeft}
                      </td>
                      <td className="px-4 py-2 text-right">
                        {formatNum(line.batchNeed)}
                      </td>
                      <td className="px-4 py-2 text-right font-semibold">
                        {formatNum(line.prodQty)}
                      </td>
                      <td className="px-4 py-2 text-center">
                        {line.itemPriority}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
            <div className="flex gap-2 border-t border-slate-200 bg-slate-50 p-4 dark:border-slate-700 dark:bg-slate-800">
              <button
                type="button"
                onClick={handleAutoGenJob}
                disabled={isGenerating}
                className="inline-flex items-center gap-2 rounded-lg bg-blue-500 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-blue-600 disabled:opacity-50"
              >
                {isGenerating ? (
                  <CircularProgress size={16} sx={{ display: "block" }} />
                ) : (
                  <Hub sx={{ fontSize: 16 }} />
                )}
                自動生成工單
              </button>
              <button
                type="button"
                onClick={() => setIsDetailOpen(false)}
                disabled={isGenerating}
                className="rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-100 disabled:opacity-50 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600"
              >
                關閉
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Forecast Dialog */}
      {isForecastDialogOpen && (
        <div
          className="fixed inset-0 z-[1300] flex items-center justify-center p-4"
          role="dialog"
          aria-modal="true"
        >
          <div
            className="absolute inset-0 bg-black/50"
            onClick={() => setIsForecastDialogOpen(false)}
          />
          <div className="relative z-10 w-full max-w-sm rounded-lg border border-slate-200 bg-white p-4 shadow-xl dark:border-slate-700 dark:bg-slate-800 sm:max-w-md">
            <h3 className="mb-4 text-lg font-semibold text-slate-900 dark:text-white">
              準備生成預計排期
            </h3>
            <div className="flex flex-col gap-4">
              <div>
                <label
                  htmlFor="forecast-start"
                  className="mb-1 block text-sm font-medium text-slate-700 dark:text-slate-300"
                >
                  開始日期
                </label>
                <input
                  id="forecast-start"
                  type="date"
                  value={forecastStartDate}
                  onChange={(e) => setForecastStartDate(e.target.value)}
                  min={dayjs().subtract(30, "day").format("YYYY-MM-DD")}
                  className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-slate-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-100"
                />
              </div>
              <div>
                <label
                  htmlFor="forecast-days"
                  className="mb-1 block text-sm font-medium text-slate-700 dark:text-slate-300"
                >
                  排期日數
                </label>
                <input
                  id="forecast-days"
                  type="number"
                  min={1}
                  max={365}
                  value={forecastDays}
                  onChange={(e) => {
                    const val =
                      e.target.value === "" ? "" : Number(e.target.value);
                    if (
                      val === "" ||
                      (Number.isInteger(val) && val >= 1 && val <= 365)
                    ) {
                      setForecastDays(val);
                    }
                  }}
                  className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-slate-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-100"
                />
              </div>
            </div>
            <div className="mt-6 flex justify-end gap-2">
              <button
                type="button"
                onClick={() => setIsForecastDialogOpen(false)}
                className="rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm text-slate-700 hover:bg-slate-100 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600"
              >
                取消
              </button>
              <button
                type="button"
                onClick={handleConfirmForecast}
                disabled={
                  !forecastStartDate || forecastDays === "" || loading
                }
                className="inline-flex items-center gap-2 rounded-lg bg-blue-500 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-blue-600 disabled:opacity-50"
              >
                {loading ? (
                  <CircularProgress size={16} sx={{ display: "block" }} />
                ) : (
                  <ShowChart sx={{ fontSize: 16 }} />
                )}
                計算預測排期
              </button>
            </div>
          </div>
        </div>
      )}

      {/* Export Dialog */}
      {isExportDialogOpen && (
        <div
          className="fixed inset-0 z-[1300] flex items-center justify-center p-4"
          role="dialog"
          aria-modal="true"
        >
          <div
            className="absolute inset-0 bg-black/50"
            onClick={() => setIsExportDialogOpen(false)}
          />
          <div className="relative z-10 w-full max-w-xs rounded-lg border border-slate-200 bg-white p-4 shadow-xl dark:border-slate-700 dark:bg-slate-800">
            <h3 className="mb-2 text-lg font-semibold text-slate-900 dark:text-white">
              匯出排期/物料用量預計
            </h3>
            <p className="mb-4 text-sm text-slate-600 dark:text-slate-400">
              選擇要匯出的起始日期
            </p>
            <label
              htmlFor="export-from"
              className="mb-1 block text-sm font-medium text-slate-700 dark:text-slate-300"
            >
              起始日期
            </label>
            <input
              id="export-from"
              type="date"
              value={exportFromDate}
              onChange={(e) => setExportFromDate(e.target.value)}
              min={dayjs().subtract(90, "day").format("YYYY-MM-DD")}
              className="mb-4 w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-slate-900 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-100"
            />
            <div className="flex justify-end gap-2">
              <button
                type="button"
                onClick={() => setIsExportDialogOpen(false)}
                className="rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm text-slate-700 hover:bg-slate-100 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600"
              >
                取消
              </button>
              <button
                type="button"
                onClick={handleConfirmExport}
                disabled={!exportFromDate || loading}
                className="inline-flex items-center gap-2 rounded-lg bg-emerald-500 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-emerald-600 disabled:opacity-50"
              >
                {loading ? (
                  <CircularProgress size={16} sx={{ display: "block" }} />
                ) : (
                  <Download sx={{ fontSize: 16 }} />
                )}
                匯出
              </button>
            </div>
          </div>
        </div>
      )}

      {/* 排期設定 Dialog */}
      {isDailyOutPanelOpen && (
        <div
          className="fixed inset-0 z-[1300] flex items-center justify-center p-4"
          role="dialog"
          aria-modal="true"
          aria-labelledby="settings-panel-title"
        >
          <div
            className="absolute inset-0 bg-black/50"
            onClick={() => setIsDailyOutPanelOpen(false)}
          />
          <div className="relative z-10 flex max-h-[90vh] w-full max-w-6xl flex-col overflow-hidden rounded-lg border border-slate-200 bg-white shadow-xl dark:border-slate-700 dark:bg-slate-800">
            <div className="flex items-center justify-between border-b border-slate-200 bg-slate-100 px-4 py-3 dark:border-slate-700 dark:bg-slate-700/50">
              <h2 id="settings-panel-title" className="text-lg font-semibold text-slate-900 dark:text-white">
                排期設定
              </h2>
              <button
                type="button"
                onClick={() => setIsDailyOutPanelOpen(false)}
                className="rounded p-1 text-slate-500 hover:bg-slate-200 hover:text-slate-700 dark:hover:bg-slate-600 dark:hover:text-slate-200"
              >
                關閉
              </button>
            </div>
            <p className="px-4 py-2 text-sm text-slate-600 dark:text-slate-400">
              預設為過去 30 天（含今日）。設定排期每天出貨量、設定排期庫存可編輯並按列儲存。
            </p>
            <div className="max-h-[60vh] overflow-auto">
              {itemDailyOutLoading ? (
                <div className="flex items-center justify-center py-12">
                  <CircularProgress />
                </div>
              ) : (
                <table className="w-full min-w-[900px] text-left text-sm">
                  <thead className="sticky top-0 bg-slate-50 dark:bg-slate-700">
                    <tr>
                      <th className="px-4 py-2 font-bold text-slate-700 dark:text-slate-200">物料編號</th>
                      <th className="px-4 py-2 font-bold text-slate-700 dark:text-slate-200">物料名稱</th>
                      <th className="px-4 py-2 font-bold text-slate-700 dark:text-slate-200">單位</th>
                      <th className="px-4 py-2 text-right font-bold text-slate-700 dark:text-slate-200">庫存</th>
                      <th className="px-4 py-2 text-left font-bold text-slate-700 dark:text-slate-200">設定排期庫存</th>
                      <th className="px-4 py-2 text-right font-bold text-slate-700 dark:text-slate-200">過去平均出貨量</th>
                      <th className="px-4 py-2 text-left font-bold text-slate-700 dark:text-slate-200">設定排期每天出貨量</th>
                      <th className="px-4 py-2 text-center font-bold text-slate-700 dark:text-slate-200">咖啡</th>
                      <th className="px-4 py-2 text-center font-bold text-slate-700 dark:text-slate-200">茶</th>
                      <th className="px-4 py-2 text-center font-bold text-slate-700 dark:text-slate-200">檸檬</th>
                    </tr>
                  </thead>
                  <tbody>
                    {itemDailyOutList.map((row, idx) => (
                      <DailyOutRow
                        key={`${row.itemCode}-${idx}`}
                        row={row}
                        onSave={handleSaveDailyQty}
                        onClear={handleClearDailyQty}
                        onSetCoffeeOrTea={handleSetCoffeeOrTea}
                        onSetFakeOnHand={handleSetFakeOnHand}
                        onClearFakeOnHand={handleClearFakeOnHand}
                        saving={dailyOutSavingCode === row.itemCode}
                        clearing={dailyOutClearingCode === row.itemCode}
                        coffeeOrTeaUpdating={coffeeOrTeaUpdating}
                        fakeOnHandSaving={fakeOnHandSavingCode === row.itemCode}
                        fakeOnHandClearing={fakeOnHandClearingCode === row.itemCode}
                        formatNum={formatNum}
                      />
                    ))}
                  </tbody>
                </table>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function DailyOutRow({
  row,
  onSave,
  onClear,
  onSetCoffeeOrTea,
  onSetFakeOnHand,
  onClearFakeOnHand,
  saving,
  clearing,
  coffeeOrTeaUpdating,
  fakeOnHandSaving,
  fakeOnHandClearing,
  formatNum,
}: {
  row: ItemDailyOutRow;
  onSave: (itemCode: string, dailyQty: number) => void;
  onClear: (itemCode: string) => void;
  onSetCoffeeOrTea: (itemCode: string, systemType: "coffee" | "tea" | "lemon", enabled: boolean) => void;
  onSetFakeOnHand: (itemCode: string, onHandQty: number) => void;
  onClearFakeOnHand: (itemCode: string) => void;
  saving: boolean;
  clearing: boolean;
  coffeeOrTeaUpdating: string | null;
  fakeOnHandSaving: boolean;
  fakeOnHandClearing: boolean;
  formatNum: (n: any) => string;
}) {
  const [editQty, setEditQty] = useState<string>(
    row.dailyQty != null ? String(row.dailyQty) : ""
  );
  const [editFakeOnHand, setEditFakeOnHand] = useState<string>(
    row.fakeOnHandQty != null ? String(row.fakeOnHandQty) : ""
  );
  useEffect(() => {
    setEditQty(row.dailyQty != null ? String(row.dailyQty) : "");
  }, [row.dailyQty]);
  useEffect(() => {
    setEditFakeOnHand(row.fakeOnHandQty != null ? String(row.fakeOnHandQty) : "");
  }, [row.fakeOnHandQty]);
  const numVal = parseFloat(editQty);
  const isValid = !Number.isNaN(numVal) && numVal >= 0;
  const hasSetQty = row.dailyQty != null;
  const fakeOnHandNum = parseFloat(editFakeOnHand);
  const isValidFakeOnHand = !Number.isNaN(fakeOnHandNum) && fakeOnHandNum >= 0;
  const hasSetFakeOnHand = row.fakeOnHandQty != null;
  const isCoffee = (row.isCoffee ?? 0) > 0;
  const isTea = (row.isTea ?? 0) > 0;
  const isLemon = (row.isLemon ?? 0) > 0;
  const updatingCoffee = coffeeOrTeaUpdating === `${row.itemCode}-coffee`;
  const updatingTea = coffeeOrTeaUpdating === `${row.itemCode}-tea`;
  const updatingLemon = coffeeOrTeaUpdating === `${row.itemCode}-lemon`;
  return (
    <tr className="border-t border-slate-200 text-slate-700 hover:bg-slate-50 dark:border-slate-700 dark:text-slate-300 dark:hover:bg-slate-700/30">
      <td className="px-4 py-2 font-medium">{row.itemCode}</td>
      <td className="px-4 py-2">{row.itemName}</td>
      <td className="px-4 py-2">{row.unit ?? ""}</td>
      <td className="px-4 py-2 text-right">{formatNum(row.onHandQty)}</td>
      <td className="px-4 py-2 text-left">
        <div className="flex items-center justify-start gap-0.5">
          <input
            type="number"
            min={0}
            step={1}
            value={editFakeOnHand}
            onChange={(e) => setEditFakeOnHand(e.target.value)}
            onBlur={() => {
              if (isValidFakeOnHand) onSetFakeOnHand(row.itemCode, fakeOnHandNum);
            }}
            onKeyDown={(e) => {
              if (e.key === "Enter" && isValidFakeOnHand) onSetFakeOnHand(row.itemCode, fakeOnHandNum);
            }}
            className="w-24 rounded border border-slate-300 bg-white px-2 py-1 text-left text-slate-900 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-100"
          />
          {hasSetFakeOnHand && (
            <button
              type="button"
              disabled={fakeOnHandClearing}
              onClick={() => onClearFakeOnHand(row.itemCode)}
              title="清除設定排期庫存"
              className="rounded p-0.5 text-slate-400 hover:bg-slate-200 hover:text-slate-600 disabled:opacity-50 dark:hover:bg-slate-600 dark:hover:text-slate-200"
            >
              {fakeOnHandClearing ? <CircularProgress size={14} sx={{ display: "block" }} /> : <Clear sx={{ fontSize: 18 }} />}
            </button>
          )}
        </div>
      </td>
      <td className="px-4 py-2 text-right">{formatNum(row.avgQtyLastMonth)}</td>
      <td className="px-4 py-2 text-left">
        <div className="flex items-center justify-start gap-0.5">
          <input
            type="number"
            min={0}
            step={1}
            value={editQty}
            onChange={(e) => setEditQty(e.target.value)}
            onBlur={() => {
              if (isValid) onSave(row.itemCode, numVal);
            }}
            onKeyDown={(e) => {
              if (e.key === "Enter" && isValid) onSave(row.itemCode, numVal);
            }}
            className="w-24 rounded border border-slate-300 bg-white px-2 py-1 text-left text-slate-900 dark:border-slate-600 dark:bg-slate-700 dark:text-slate-100"
          />
          {hasSetQty && (
            <button
              type="button"
              disabled={clearing}
              onClick={() => onClear(row.itemCode)}
              title="清除設定排期每天出貨量"
              className="rounded p-0.5 text-slate-400 hover:bg-slate-200 hover:text-slate-600 disabled:opacity-50 dark:hover:bg-slate-600 dark:hover:text-slate-200"
            >
              {clearing ? <CircularProgress size={14} sx={{ display: "block" }} /> : <Clear sx={{ fontSize: 18 }} />}
            </button>
          )}
        </div>
      </td>
      <td className="px-4 py-2 text-center">
        <label className="inline-flex cursor-pointer items-center gap-1">
          <input
            type="checkbox"
            checked={isCoffee}
            disabled={updatingCoffee}
            onChange={(e) => onSetCoffeeOrTea(row.itemCode, "coffee", e.target.checked)}
            className="h-4 w-4 rounded border-slate-300 text-blue-500 focus:ring-blue-500"
          />
          {updatingCoffee && <CircularProgress size={14} sx={{ display: "block" }} />}
        </label>
      </td>
      <td className="px-4 py-2 text-center">
        <label className="inline-flex cursor-pointer items-center gap-1">
          <input
            type="checkbox"
            checked={isTea}
            disabled={updatingTea}
            onChange={(e) => onSetCoffeeOrTea(row.itemCode, "tea", e.target.checked)}
            className="h-4 w-4 rounded border-slate-300 text-blue-500 focus:ring-blue-500"
          />
          {updatingTea && <CircularProgress size={14} sx={{ display: "block" }} />}
        </label>
      </td>
      <td className="px-4 py-2 text-center">
        <label className="inline-flex cursor-pointer items-center gap-1">
          <input
            type="checkbox"
            checked={isLemon}
            disabled={updatingLemon}
            onChange={(e) => onSetCoffeeOrTea(row.itemCode, "lemon", e.target.checked)}
            className="h-4 w-4 rounded border-slate-300 text-blue-500 focus:ring-blue-500"
          />
          {updatingLemon && <CircularProgress size={14} sx={{ display: "block" }} />}
        </label>
      </td>
    </tr>
  );
}
