"use client";

import React, { useCallback, useMemo, useState } from "react";
import {
  Box,
  Typography,
  Skeleton,
  Alert,
  TextField,
  FormControl,
  InputLabel,
  Select,
  MenuItem,
  Autocomplete,
  Chip,
} from "@mui/material";
import dynamic from "next/dynamic";
import LocalShipping from "@mui/icons-material/LocalShipping";
import {
  fetchDeliveryOrderByDate,
  fetchTopDeliveryItems,
  fetchTopDeliveryItemsItemOptions,
  fetchStaffDeliveryPerformance,
  fetchStaffDeliveryPerformanceHandlers,
  type StaffOption,
  type TopDeliveryItemOption,
} from "@/app/api/chart/client";
import ChartCard from "../_components/ChartCard";
import DateRangeSelect from "../_components/DateRangeSelect";
import { toDateRange, DEFAULT_RANGE_DAYS, TOP_ITEMS_LIMIT_OPTIONS } from "../_components/constants";

const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false });

const PAGE_TITLE = "發貨與配送";

type Criteria = {
  delivery: { rangeDays: number };
  topItems: { rangeDays: number; limit: number };
  staffPerf: { rangeDays: number };
};

const defaultCriteria: Criteria = {
  delivery: { rangeDays: DEFAULT_RANGE_DAYS },
  topItems: { rangeDays: DEFAULT_RANGE_DAYS, limit: 10 },
  staffPerf: { rangeDays: DEFAULT_RANGE_DAYS },
};

export default function DeliveryChartPage() {
  const [criteria, setCriteria] = useState<Criteria>(defaultCriteria);
  const [topItemsSelected, setTopItemsSelected] = useState<TopDeliveryItemOption[]>([]);
  const [topItemOptions, setTopItemOptions] = useState<TopDeliveryItemOption[]>([]);
  const [staffSelected, setStaffSelected] = useState<StaffOption[]>([]);
  const [staffOptions, setStaffOptions] = useState<StaffOption[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [chartData, setChartData] = useState<{
    delivery: { date: string; orderCount: number; totalQty: number }[];
    topItems: { itemCode: string; itemName: string; totalQty: number }[];
    staffPerf: { date: string; staffName: string; orderCount: number; totalMinutes: number }[];
  }>({ delivery: [], topItems: [], staffPerf: [] });
  const [loadingCharts, setLoadingCharts] = useState<Record<string, boolean>>({});

  const updateCriteria = useCallback(
    <K extends keyof Criteria>(key: K, updater: (prev: Criteria[K]) => Criteria[K]) => {
      setCriteria((prev) => ({ ...prev, [key]: updater(prev[key]) }));
    },
    []
  );
  const setChartLoading = useCallback((key: string, value: boolean) => {
    setLoadingCharts((prev) => (prev[key] === value ? prev : { ...prev, [key]: value }));
  }, []);

  React.useEffect(() => {
    const { startDate: s, endDate: e } = toDateRange(criteria.delivery.rangeDays);
    setChartLoading("delivery", true);
    fetchDeliveryOrderByDate(s, e)
      .then((data) =>
        setChartData((prev) => ({
          ...prev,
          delivery: data as { date: string; orderCount: number; totalQty: number }[],
        }))
      )
      .catch((err) => setError(err instanceof Error ? err.message : "Request failed"))
      .finally(() => setChartLoading("delivery", false));
  }, [criteria.delivery, setChartLoading]);

  React.useEffect(() => {
    const { startDate: s, endDate: e } = toDateRange(criteria.topItems.rangeDays);
    setChartLoading("topItems", true);
    fetchTopDeliveryItems(
      s,
      e,
      criteria.topItems.limit,
      topItemsSelected.length > 0 ? topItemsSelected.map((o) => o.itemCode) : undefined
    )
      .then((data) =>
        setChartData((prev) => ({
          ...prev,
          topItems: data as { itemCode: string; itemName: string; totalQty: number }[],
        }))
      )
      .catch((err) => setError(err instanceof Error ? err.message : "Request failed"))
      .finally(() => setChartLoading("topItems", false));
  }, [criteria.topItems, topItemsSelected, setChartLoading]);

  React.useEffect(() => {
    const { startDate: s, endDate: e } = toDateRange(criteria.staffPerf.rangeDays);
    const staffNos = staffSelected.length > 0 ? staffSelected.map((o) => o.staffNo) : undefined;
    setChartLoading("staffPerf", true);
    fetchStaffDeliveryPerformance(s, e, staffNos)
      .then((data) =>
        setChartData((prev) => ({
          ...prev,
          staffPerf: data as {
            date: string;
            staffName: string;
            orderCount: number;
            totalMinutes: number;
          }[],
        }))
      )
      .catch((err) => setError(err instanceof Error ? err.message : "Request failed"))
      .finally(() => setChartLoading("staffPerf", false));
  }, [criteria.staffPerf, staffSelected, setChartLoading]);

  React.useEffect(() => {
    fetchStaffDeliveryPerformanceHandlers()
      .then(setStaffOptions)
      .catch(() => setStaffOptions([]));
  }, []);
  React.useEffect(() => {
    const { startDate: s, endDate: e } = toDateRange(criteria.topItems.rangeDays);
    fetchTopDeliveryItemsItemOptions(s, e).then(setTopItemOptions).catch(() => setTopItemOptions([]));
  }, [criteria.topItems.rangeDays]);

  const staffPerfByStaff = useMemo(() => {
    const map = new Map<string, { orderCount: number; totalMinutes: number }>();
    for (const r of chartData.staffPerf) {
      const name = r.staffName || "Unknown";
      const cur = map.get(name) ?? { orderCount: 0, totalMinutes: 0 };
      map.set(name, {
        orderCount: cur.orderCount + r.orderCount,
        totalMinutes: cur.totalMinutes + r.totalMinutes,
      });
    }
    return Array.from(map.entries()).map(([staffName, v]) => ({
      staffName,
      orderCount: v.orderCount,
      totalMinutes: v.totalMinutes,
      avgMinutesPerOrder: v.orderCount > 0 ? Math.round(v.totalMinutes / v.orderCount) : 0,
    }));
  }, [chartData.staffPerf]);

  return (
    <Box sx={{ maxWidth: 1200, mx: "auto" }}>
      <Typography variant="h5" sx={{ mb: 2, fontWeight: 600, display: "flex", alignItems: "center", gap: 1 }}>
        <LocalShipping /> {PAGE_TITLE}
      </Typography>
      {error && (
        <Alert severity="error" sx={{ mb: 2 }} onClose={() => setError(null)}>
          {error}
        </Alert>
      )}

      <ChartCard
        title="按日期發貨單數量"
        exportFilename="發貨單數量_按日期"
        exportData={chartData.delivery.map((d) => ({ 日期: d.date, 單數: d.orderCount }))}
        filters={
          <DateRangeSelect
            value={criteria.delivery.rangeDays}
            onChange={(v) => updateCriteria("delivery", (c) => ({ ...c, rangeDays: v }))}
          />
        }
      >
        {loadingCharts.delivery ? (
          <Skeleton variant="rectangular" height={320} />
        ) : (
          <ApexCharts
            options={{
              chart: { type: "bar" },
              xaxis: { categories: chartData.delivery.map((d) => d.date) },
              yaxis: { title: { text: "單數" } },
              plotOptions: { bar: { horizontal: false, columnWidth: "60%" } },
              dataLabels: { enabled: false },
            }}
            series={[{ name: "單數", data: chartData.delivery.map((d) => d.orderCount) }]}
            type="bar"
            width="100%"
            height={320}
          />
        )}
      </ChartCard>

      <ChartCard
        title="發貨數量排行（按物料）"
        exportFilename="發貨數量排行_按物料"
        exportData={chartData.topItems.map((i) => ({ 物料編碼: i.itemCode, 物料名稱: i.itemName, 數量: i.totalQty }))}
        filters={
          <>
            <DateRangeSelect
              value={criteria.topItems.rangeDays}
              onChange={(v) => updateCriteria("topItems", (c) => ({ ...c, rangeDays: v }))}
            />
            <FormControl size="small" sx={{ minWidth: 100 }}>
              <InputLabel>顯示</InputLabel>
              <Select
                value={criteria.topItems.limit}
                label="顯示"
                onChange={(e) => updateCriteria("topItems", (c) => ({ ...c, limit: Number(e.target.value) }))}
              >
                {TOP_ITEMS_LIMIT_OPTIONS.map((n) => (
                  <MenuItem key={n} value={n}>
                    {n} 條
                  </MenuItem>
                ))}
              </Select>
            </FormControl>
            <Autocomplete
              multiple
              size="small"
              options={topItemOptions}
              value={topItemsSelected}
              onChange={(_, v) => setTopItemsSelected(v)}
              getOptionLabel={(opt) => [opt.itemCode, opt.itemName].filter(Boolean).join(" - ") || opt.itemCode}
              isOptionEqualToValue={(a, b) => a.itemCode === b.itemCode}
              renderInput={(params) => (
                <TextField {...params} label="物料" placeholder="不選則全部" />
              )}
              renderTags={(value, getTagProps) =>
                value.map((option, index) => {
                  const { key: _key, ...tagProps } = getTagProps({ index });
                  return (
                    <Chip
                      key={option.itemCode}
                      label={[option.itemCode, option.itemName].filter(Boolean).join(" - ")}
                      size="small"
                      {...tagProps}
                    />
                  );
                })
              }
              sx={{ minWidth: 280 }}
            />
          </>
        }
      >
        {loadingCharts.topItems ? (
          <Skeleton variant="rectangular" height={320} />
        ) : (
          <ApexCharts
            options={{
              chart: { type: "bar" },
              xaxis: {
                categories: chartData.topItems.map((i) => `${i.itemCode} ${i.itemName}`.trim()),
              },
              plotOptions: { bar: { horizontal: true, barHeight: "70%" } },
              dataLabels: { enabled: true },
            }}
            series={[{ name: "數量", data: chartData.topItems.map((i) => i.totalQty) }]}
            type="bar"
            width="100%"
            height={Math.max(320, chartData.topItems.length * 36)}
          />
        )}
      </ChartCard>

      <ChartCard
        title="員工發貨績效（每日揀貨數量與耗時）"
        exportFilename="員工發貨績效"
        exportData={chartData.staffPerf.map((r) => ({ 日期: r.date, 員工: r.staffName, 揀單數: r.orderCount, 總分鐘: r.totalMinutes }))}
        filters={
          <>
            <DateRangeSelect
              value={criteria.staffPerf.rangeDays}
              onChange={(v) => updateCriteria("staffPerf", (c) => ({ ...c, rangeDays: v }))}
            />
            <Autocomplete
              multiple
              size="small"
              options={staffOptions}
              value={staffSelected}
              onChange={(_, v) => setStaffSelected(v)}
              getOptionLabel={(opt) => [opt.staffNo, opt.name].filter(Boolean).join(" - ") || opt.staffNo}
              isOptionEqualToValue={(a, b) => a.staffNo === b.staffNo}
              renderInput={(params) => (
                <TextField {...params} label="員工" placeholder="不選則全部" />
              )}
              renderTags={(value, getTagProps) =>
                value.map((option, index) => {
                  const { key: _key, ...tagProps } = getTagProps({ index });
                  return (
                    <Chip
                      key={option.staffNo}
                      label={[option.staffNo, option.name].filter(Boolean).join(" - ")}
                      size="small"
                      {...tagProps}
                    />
                  );
                })
              }
              sx={{ minWidth: 260 }}
            />
          </>
        }
      >
        {loadingCharts.staffPerf ? (
          <Skeleton variant="rectangular" height={320} />
        ) : chartData.staffPerf.length === 0 ? (
          <Typography color="text.secondary" sx={{ py: 3 }}>
            此日期範圍內尚無完成之發貨單，或無揀貨人資料。請更換日期範圍或確認發貨單（DO）已由員工完成並有紀錄揀貨時間。
          </Typography>
        ) : (
          <>
            <Box sx={{ mb: 2 }}>
              <Typography variant="subtitle2" color="text.secondary" gutterBottom>
                週期內每人揀單數及總耗時（首揀至完成）
              </Typography>
              <Box
                component="table"
                sx={{
                  width: "100%",
                  borderCollapse: "collapse",
                  "& th, & td": {
                    border: "1px solid",
                    borderColor: "divider",
                    px: 1.5,
                    py: 1,
                    textAlign: "left",
                  },
                  "& th": { bgcolor: "action.hover", fontWeight: 600 },
                }}
              >
                <thead>
                  <tr>
                    <th>員工</th>
                    <th>揀單數</th>
                    <th>總分鐘</th>
                    <th>平均分鐘/單</th>
                  </tr>
                </thead>
                <tbody>
                  {staffPerfByStaff.length === 0 ? (
                    <tr>
                      <td colSpan={4}>無數據</td>
                    </tr>
                  ) : (
                    staffPerfByStaff.map((row) => (
                      <tr key={row.staffName}>
                        <td>{row.staffName}</td>
                        <td>{row.orderCount}</td>
                        <td>{row.totalMinutes}</td>
                        <td>{row.avgMinutesPerOrder}</td>
                      </tr>
                    ))
                  )}
                </tbody>
              </Box>
            </Box>
            <Typography variant="subtitle2" color="text.secondary" gutterBottom>
              每日按員工單數
            </Typography>
            <ApexCharts
              options={{
                chart: { type: "bar", stacked: true },
                xaxis: {
                  categories: Array.from(new Set(chartData.staffPerf.map((r) => r.date))).sort(),
                },
                yaxis: { title: { text: "單數" } },
                plotOptions: { bar: { columnWidth: "60%" } },
                dataLabels: { enabled: false },
                legend: { position: "top" },
              }}
              series={(() => {
                const staffNames = Array.from(new Set(chartData.staffPerf.map((r) => r.staffName))).filter(Boolean).sort();
                const dates = Array.from(new Set(chartData.staffPerf.map((r) => r.date))).sort();
                return staffNames.map((name) => ({
                  name: name || "Unknown",
                  data: dates.map((d) => {
                    const row = chartData.staffPerf.find((r) => r.date === d && r.staffName === name);
                    return row ? row.orderCount : 0;
                  }),
                }));
              })()}
              type="bar"
              width="100%"
              height={320}
            />
          </>
        )}
      </ChartCard>
    </Box>
  );
}
