"use client";

import React from "react";
import {
  Box,
  Button,
  Checkbox,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControlLabel,
  IconButton,
  Radio,
  RadioGroup,
  Stack,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  TextField,
  Typography,
} from "@mui/material";
import KeyboardArrowDown from "@mui/icons-material/KeyboardArrowDown";
import KeyboardArrowUp from "@mui/icons-material/KeyboardArrowUp";
import { useTranslation } from "react-i18next";
import { GridRowSelectionModel } from "@mui/x-data-grid";
import {
  fetchOrderedItemOrderItems,
  fetchUnorderedItemOrderItems,
  ItemOrderItem,
  searchUnorderedItemOrderItems,
  saveItemOrder,
} from "@/app/api/settings/item/itemOrderActions";

type Row = {
  id: number;
  code: string;
  name: string;
  itemOrder: number;
};

function normalize(s: string) {
  return s.trim().toLowerCase();
}

function onlyDigits(s: string) {
  return /^\d+$/.test(s);
}

function normalizeCode(s: string) {
  return normalize(s).replace(/[^a-z0-9]/g, "");
}

function codeMatches(code: string, q: string) {
  const query = normalizeCode(q);
  if (!query) return true;
  const c = normalizeCode(code);
  if (c.includes(query)) return true;
  // allow searching by trailing digits: "1074" matches "pp1074"
  if (onlyDigits(query)) {
    const digits = c.replace(/^[a-z]+/, "");
    return digits.includes(query);
  }
  return false;
}

function toRows(items: ItemOrderItem[]): Row[] {
  return items
    .filter((x) => x.id != null)
    .map((x, idx) => ({
      id: x.id,
      code: x.code ?? "",
      name: x.name ?? "",
      itemOrder: typeof x.itemOrder === "number" ? x.itemOrder : idx + 1,
    }))
    .sort((a, b) => a.itemOrder - b.itemOrder);
}

function reorderByIndex<T>(arr: T[], from: number, to: number) {
  const next = arr.slice();
  const [item] = next.splice(from, 1);
  next.splice(to, 0, item);
  return next;
}

export default function PickOrderSequenceTab() {
  const { t } = useTranslation("finishedgoodmanagement");
  const rowRefs = React.useRef(new Map<number, HTMLTableRowElement | null>());

  const [loading, setLoading] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const [rows, setRows] = React.useState<Row[]>([]);
  const [originalIds, setOriginalIds] = React.useState<number[]>([]);
  const [selectionModel, setSelectionModel] = React.useState<GridRowSelectionModel>([]);

  const [filterCode, setFilterCode] = React.useState("");
  const [filterName, setFilterName] = React.useState("");
  const [jumpQuery, setJumpQuery] = React.useState("");

  const [addOpen, setAddOpen] = React.useState(false);
  const [addSearch, setAddSearch] = React.useState("");
  const [addLoading, setAddLoading] = React.useState(false);
  const [addRows, setAddRows] = React.useState<Row[]>([]);
  const [addSelection, setAddSelection] = React.useState<GridRowSelectionModel>([]);
  const [insertAt, setInsertAt] = React.useState<number | "">("");
  const [insertPlacement, setInsertPlacement] = React.useState<"before" | "after">("before");

  const [moveDialogOpen, setMoveDialogOpen] = React.useState(false);
  const [moveRowId, setMoveRowId] = React.useState<number | null>(null);
  const [moveToOrder, setMoveToOrder] = React.useState<number | "">("");
  const [movePlacement, setMovePlacement] = React.useState<"before" | "after">("before");

  const hasUnsavedChanges = React.useMemo(() => {
    const ids = rows.map((r) => r.id);
    if (ids.length !== originalIds.length) return true;
    for (let i = 0; i < ids.length; i++) if (ids[i] !== originalIds[i]) return true;
    return false;
  }, [rows, originalIds]);

  const refresh = React.useCallback(async () => {
    setLoading(true);
    try {
      const items = await fetchOrderedItemOrderItems();
      const r = toRows(items);
      setRows(r.map((x, i) => ({ ...x, itemOrder: i + 1 })));
      setOriginalIds(r.map((x) => x.id));
      setSelectionModel([]);
    } finally {
      setLoading(false);
    }
  }, []);

  React.useEffect(() => {
    refresh();
  }, [refresh]);

  const filteredRows = React.useMemo(() => {
    const qcRaw = filterCode.trim();
    const qn = normalize(filterName);
    const qcNorm = normalizeCode(qcRaw);
    if (!qcNorm && !qn) return rows;
    return rows.filter((r) => {
      const okCode = !qcNorm || codeMatches(r.code, qcRaw);
      const okName = !qn || normalize(r.name).includes(qn);
      return okCode && okName;
    });
  }, [filterCode, filterName, rows]);

  const MainFooter = React.useMemo(() => {
    const Footer = () => {
      const total = filteredRows.length;
      const from = total === 0 ? 0 : 1;
      const to = total;
      return (
        <Box sx={{ px: 2, py: 1, display: "flex", justifyContent: "flex-end", color: "text.secondary" }}>
          <Typography variant="body2">{`${from} ~ ${to} / ${total}`}</Typography>
        </Box>
      );
    };
    return Footer;
  }, [filteredRows.length]);

  const AddFooter = React.useMemo(() => {
    const Footer = () => {
      const total = addRows.length;
      const from = total === 0 ? 0 : 1;
      const to = total;
      return (
        <Box sx={{ px: 2, py: 1, display: "flex", justifyContent: "flex-end", color: "text.secondary" }}>
          <Typography variant="body2">{`${from} ~ ${to} / ${total}`}</Typography>
        </Box>
      );
    };
    return Footer;
  }, [addRows.length]);

  const selectedId = (selectionModel?.[0] as number | undefined) ?? undefined;
  const selectedIndex = selectedId != null ? rows.findIndex((r) => r.id === selectedId) : -1;

  const moveRowByIdTo = React.useCallback(
    (rowId: number, toIndex: number) => {
      const from = rows.findIndex((r) => r.id === rowId);
      if (from < 0) return;
      const to = Math.max(0, Math.min(rows.length - 1, toIndex));
      if (to === from) return;
      const next = reorderByIndex(rows, from, to).map((r, i) => ({ ...r, itemOrder: i + 1 }));
      setRows(next);
      const newId = next[to]?.id;
      if (newId != null) setSelectionModel([newId]);
      queueMicrotask(() => rowRefs.current.get(newId)?.scrollIntoView({ block: "center" }));
    },
    [rows],
  );

  const moveSelected = React.useCallback(
    (delta: number) => {
      if (selectedIndex < 0) return;
      const to = Math.max(0, Math.min(rows.length - 1, selectedIndex + delta));
      if (to === selectedIndex) return;
      const next = reorderByIndex(rows, selectedIndex, to).map((r, i) => ({ ...r, itemOrder: i + 1 }));
      setRows(next);
      const newId = next[to]?.id;
      if (newId != null) setSelectionModel([newId]);
      queueMicrotask(() => rowRefs.current.get(newId)?.scrollIntoView({ block: "center" }));
    },
    [rows, selectedIndex],
  );

  const moveSelectedTo = React.useCallback(
    (toIndex: number) => {
      if (selectedIndex < 0) return;
      const to = Math.max(0, Math.min(rows.length - 1, toIndex));
      if (to === selectedIndex) return;
      const next = reorderByIndex(rows, selectedIndex, to).map((r, i) => ({ ...r, itemOrder: i + 1 }));
      setRows(next);
      const newId = next[to]?.id;
      if (newId != null) setSelectionModel([newId]);
      queueMicrotask(() => rowRefs.current.get(newId)?.scrollIntoView({ block: "center" }));
    },
    [rows, selectedIndex],
  );

  const jumpTo = React.useCallback(() => {
    const qRaw = jumpQuery.trim();
    const q = normalize(qRaw);
    if (!q) return;
    const idx = rows.findIndex((r) => codeMatches(r.code, qRaw) || normalize(r.name).includes(q));
    if (idx < 0) return;
    const id = rows[idx].id;
    setSelectionModel([id]);
    queueMicrotask(() => rowRefs.current.get(id)?.scrollIntoView({ block: "center" }));
  }, [jumpQuery, rows]);

  const openAdd = React.useCallback(async () => {
    setAddOpen(true);
    setAddSearch("");
    setAddSelection([]);
    setInsertAt(selectedIndex >= 0 ? selectedIndex + 2 : rows.length + 1);
    setAddLoading(true);
    try {
      // Do not fetch everything by default; wait for user search
      setAddRows([]);
    } finally {
      setAddLoading(false);
    }
  }, [rows.length, selectedIndex]);

  const searchAdd = React.useCallback(async () => {
    const q = addSearch.trim();
    if (!q) {
      setAddRows([]);
      setAddSelection([]);
      return;
    }
    setAddLoading(true);
    try {
      // Search across ALL items without order (not only FG), with server-side LIMIT for performance
      const items = await searchUnorderedItemOrderItems(q, undefined, 200);
      setAddRows(toRows(items).map((x, i) => ({ ...x, itemOrder: i + 1 })));
      setAddSelection([]);
    } finally {
      setAddLoading(false);
    }
  }, [addSearch]);

  const confirmAdd = React.useCallback(() => {
    const selectedIds = new Set(addSelection as number[]);
    const picked = addRows.filter((r) => selectedIds.has(r.id));
    if (picked.length === 0) {
      setAddOpen(false);
      return;
    }
    const existing = new Set(rows.map((r) => r.id));
    const appended = picked.filter((r) => !existing.has(r.id));
    const base = rows.slice();
    const idx0 =
      typeof insertAt === "number" && Number.isFinite(insertAt) ? Math.max(1, Math.floor(insertAt)) - 1 : base.length;
    const insertIndexRaw = insertPlacement === "after" ? idx0 + 1 : idx0;
    const insertIndex = Math.max(0, Math.min(base.length, insertIndexRaw));
    const next = [...base.slice(0, insertIndex), ...appended, ...base.slice(insertIndex)].map((r, i) => ({
      ...r,
      itemOrder: i + 1,
    }));
    setRows(next);
    setAddOpen(false);
  }, [addRows, addSelection, insertAt, insertPlacement, rows]);

  const openMoveDialog = React.useCallback(
    (rowId: number) => {
      const row = rows.find((r) => r.id === rowId);
      setMoveRowId(rowId);
      setMoveToOrder(row?.itemOrder ?? "");
      setMovePlacement("before");
      setMoveDialogOpen(true);
    },
    [rows],
  );

  const confirmMoveDialog = React.useCallback(() => {
    if (moveRowId == null) return setMoveDialogOpen(false);
    if (moveToOrder === "") return;
    const n = Number(moveToOrder);
    if (!Number.isFinite(n) || n < 1) return;
    const baseIndex = Math.floor(n) - 1;
    const toIndex = movePlacement === "after" ? baseIndex + 1 : baseIndex;
    moveRowByIdTo(moveRowId, toIndex);
    setMoveDialogOpen(false);
  }, [movePlacement, moveRowByIdTo, moveRowId, moveToOrder]);

  const onSave = React.useCallback(async () => {
    setSaving(true);
    try {
      await saveItemOrder(rows.map((r) => r.id));
      await refresh();
    } finally {
      setSaving(false);
    }
  }, [refresh, rows]);

  const isAllAddSelected = React.useMemo(() => {
    if (addRows.length === 0) return false;
    return (addSelection as number[]).length === addRows.length;
  }, [addRows.length, addSelection]);

  const insertAtNumber = React.useMemo(() => {
    if (insertAt === "") return null;
    const n = Number(insertAt);
    if (!Number.isFinite(n)) return null;
    return Math.floor(n);
  }, [insertAt]);

  const isInsertAtValid = React.useMemo(() => {
    return insertAtNumber != null && insertAtNumber >= 1;
  }, [insertAtNumber]);

  const canConfirmAdd = React.useMemo(() => {
    return (addSelection as number[]).length > 0 && isInsertAtValid;
  }, [addSelection, isInsertAtValid]);

  const toggleAddSelectAll = React.useCallback(() => {
    if (isAllAddSelected) setAddSelection([]);
    else setAddSelection(addRows.map((r) => r.id));
  }, [addRows, isAllAddSelected]);

  return (
    <Box>
      <Stack
        direction={{ xs: "column", md: "row" }}
        spacing={1.5}
        sx={{ mb: 1.5, alignItems: { xs: "stretch", md: "center" } }}
      >
        <TextField
          size="small"
          label={t("Item Code")}
          value={filterCode}
          onChange={(e) => setFilterCode(e.target.value)}
          sx={{ width: { xs: "100%", md: 180 } }}
        />

        <TextField
          size="small"
          label={t("Item Name")}
          value={filterName}
          onChange={(e) => setFilterName(e.target.value)}
          sx={{ width: { xs: "100%", md: 220 } }}
        />

        <TextField
          size="small"
          label={t("Search & Jump")}
          value={jumpQuery}
          onChange={(e) => setJumpQuery(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === "Enter") jumpTo();
          }}
          sx={{ width: { xs: "100%", md: 260 } }}
        />

        <Stack direction="row" spacing={1} sx={{ flexWrap: "wrap", alignItems: "center" }}>
          <Button size="small" variant="outlined" onClick={jumpTo} sx={{ height: 36 }}>
            {t("Jump")}
          </Button>
          <Button
            size="small"
            variant="outlined"
            onClick={() => moveSelected(-1)}
            disabled={selectedIndex <= 0}
            sx={{ height: 36 }}
          >
            {t("Move Up")}
          </Button>
          <Button
            size="small"
            variant="outlined"
            onClick={() => moveSelected(1)}
            disabled={selectedIndex < 0 || selectedIndex >= rows.length - 1}
            sx={{ height: 36 }}
          >
            {t("Move Down")}
          </Button>
          <Button
            size="small"
            variant="outlined"
            onClick={() => moveSelectedTo(0)}
            disabled={selectedIndex <= 0}
            sx={{ height: 36 }}
          >
            {t("Move Top")}
          </Button>
          <Button
            size="small"
            variant="outlined"
            onClick={() => moveSelectedTo(rows.length - 1)}
            disabled={selectedIndex < 0 || selectedIndex >= rows.length - 1}
            sx={{ height: 36 }}
          >
            {t("Move Bottom")}
          </Button>
        </Stack>

        <Box sx={{ flex: 1 }} />

        <Stack direction="row" spacing={1} sx={{ alignItems: "center" }}>
          <Button size="small" variant="contained" onClick={openAdd} sx={{ height: 36 }}>
            {t("Add Item")}
          </Button>
          <Button
            size="small"
            variant="contained"
            color="success"
            onClick={onSave}
            disabled={!hasUnsavedChanges || saving}
            sx={{ height: 36 }}
          >
            {saving ? t("Saving") : t("Save")}
          </Button>
          <Button size="small" variant="outlined" onClick={refresh} disabled={loading || saving} sx={{ height: 36 }}>
            {t("Refresh")}
          </Button>
        </Stack>
      </Stack>

      {hasUnsavedChanges && (
        <Typography variant="body2" sx={{ mb: 1, color: "warning.dark" }}>
          {t("Unsaved changes")}
        </Typography>
      )}

      <Box sx={{ width: "100%" }}>
        <TableContainer sx={{ maxHeight: 640, border: "1px solid", borderColor: "divider", borderRadius: 1 }}>
          <Table stickyHeader size="small">
            <TableHead>
              <TableRow>
                <TableCell sx={{ width: 110 }}>{t("Order")}</TableCell>
                <TableCell sx={{ width: 160 }}>{t("Code")}</TableCell>
                <TableCell>{t("Name")}</TableCell>
                <TableCell sx={{ width: 140 }}>{t("Shipping Warehouse")}</TableCell>
                <TableCell sx={{ width: 140 }}>{t("Receiving Warehouse")}</TableCell>
                <TableCell sx={{ width: 120 }}>{t("Actions")}</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {loading ? (
                <TableRow>
                  <TableCell colSpan={6}>{t("Loading")}</TableCell>
                </TableRow>
              ) : filteredRows.length === 0 ? (
                <TableRow>
                  <TableCell colSpan={6}>{t("No data available")}</TableCell>
                </TableRow>
              ) : (
                filteredRows.map((r) => (
                  <TableRow
                    key={r.id}
                    ref={(el) => rowRefs.current.set(r.id, el)}
                    hover
                    selected={selectedId === r.id}
                    onClick={() => setSelectionModel([r.id])}
                    sx={{ cursor: "pointer" }}
                  >
                    <TableCell>
                      <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
                        <Typography sx={{ minWidth: 36, textAlign: "right", fontWeight: 600 }}>
                          {r.itemOrder}
                        </Typography>
                        <Stack direction="column" spacing={0} sx={{ ml: 0.5 }}>
                          <IconButton
                            size="small"
                            onClick={(e) => {
                              e.stopPropagation();
                              setSelectionModel([r.id]);
                              moveRowByIdTo(r.id, r.itemOrder - 2);
                            }}
                            disabled={r.itemOrder <= 1}
                            sx={{
                              width: 40,
                              height: 30,
                              border: "1px solid",
                              borderColor: "divider",
                              borderRadius: 1,
                              p: 0,
                            }}
                          >
                            <KeyboardArrowUp />
                          </IconButton>
                          <IconButton
                            size="small"
                            onClick={(e) => {
                              e.stopPropagation();
                              setSelectionModel([r.id]);
                              moveRowByIdTo(r.id, r.itemOrder);
                            }}
                            disabled={r.itemOrder >= rows.length}
                            sx={{
                              width: 40,
                              height: 30,
                              border: "1px solid",
                              borderColor: "divider",
                              borderRadius: 1,
                              p: 0,
                              mt: 0.5,
                            }}
                          >
                            <KeyboardArrowDown />
                          </IconButton>
                        </Stack>
                      </Box>
                    </TableCell>
                    <TableCell>{r.code}</TableCell>
                    <TableCell>{r.name}</TableCell>
                    <TableCell />
                    <TableCell />
                    <TableCell>
                      <Button size="small" variant="outlined" onClick={() => openMoveDialog(r.id)}>
                        {t("Insert")}
                      </Button>
                    </TableCell>
                  </TableRow>
                ))
              )}
            </TableBody>
          </Table>
        </TableContainer>
        <MainFooter />
      </Box>

      <Dialog open={addOpen} onClose={() => setAddOpen(false)} fullWidth maxWidth="md">
        <DialogTitle>{t("Add Item")}</DialogTitle>
        <DialogContent>
          <Stack
            direction={{ xs: "column", md: "row" }}
            spacing={1}
            sx={{ my: 1, alignItems: { xs: "stretch", md: "center" } }}
          >
            <TextField
              size="small"
              label={t("Search")}
              value={addSearch}
              onChange={(e) => setAddSearch(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === "Enter") searchAdd();
              }}
              sx={{ width: { xs: "100%", md: 420 } }}
              helperText=" "
            />
            <TextField
              size="small"
              label={t("Insert at")}
              type="number"
              value={insertAt}
              onChange={(e) => {
                const v = e.target.value;
                if (v === "") return setInsertAt("");
                const n = Number(v);
                if (!Number.isFinite(n)) return;
                // prevent 0/negative; still allow user to type then show error
                setInsertAt(n);
              }}
              inputProps={{ min: 1 }}
              sx={{ width: { xs: "100%", md: 160 } }}
              error={insertAt !== "" && !isInsertAtValid}
              helperText={
                insertAt !== "" && !isInsertAtValid ? t("Insert position must be >= 1") : t("Order number")
              }
            />
            <Box sx={{ display: "flex", alignItems: "center", minHeight: 56 }}>
              <RadioGroup
                row
                value={insertPlacement}
                onChange={(e) => setInsertPlacement(e.target.value as "before" | "after")}
              >
                <FormControlLabel value="before" control={<Radio size="small" />} label={t("In front of")} />
                <FormControlLabel value="after" control={<Radio size="small" />} label={t("Behind")} />
              </RadioGroup>
            </Box>
            <Button variant="outlined" onClick={searchAdd}>
              {t("Search")}
            </Button>
            <Typography variant="body2" sx={{ color: "text.secondary" }}>
              {t("Only show FG items without order")}
            </Typography>
          </Stack>

          <Box sx={{ height: 520, width: "100%" }}>
            <TableContainer sx={{ maxHeight: 520, border: "1px solid", borderColor: "divider", borderRadius: 1 }}>
              <Table stickyHeader size="small">
                <TableHead>
                  <TableRow>
                    <TableCell padding="checkbox" sx={{ width: 52 }}>
                      <Checkbox checked={isAllAddSelected} onChange={toggleAddSelectAll} />
                    </TableCell>
                    <TableCell sx={{ width: 160 }}>{t("Code")}</TableCell>
                    <TableCell>{t("Name")}</TableCell>
                  <TableCell sx={{ width: 140 }}>出貨倉</TableCell>
                  <TableCell sx={{ width: 140 }}>入貨倉</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {addLoading ? (
                    <TableRow>
                    <TableCell colSpan={5}>{t("Loading")}</TableCell>
                    </TableRow>
                  ) : (
                    addRows.map((r) => {
                      const checked = (addSelection as number[]).includes(r.id);
                      return (
                        <TableRow key={r.id} hover>
                          <TableCell padding="checkbox">
                            <Checkbox
                              checked={checked}
                              onChange={() => {
                                setAddSelection((prev) => {
                                  const set = new Set(prev as number[]);
                                  if (set.has(r.id)) set.delete(r.id);
                                  else set.add(r.id);
                                  return Array.from(set);
                                });
                              }}
                            />
                          </TableCell>
                          <TableCell>{r.code}</TableCell>
                          <TableCell>{r.name}</TableCell>
                          <TableCell />
                          <TableCell />
                        </TableRow>
                      );
                    })
                  )}
                </TableBody>
              </Table>
            </TableContainer>
            <AddFooter />
          </Box>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setAddOpen(false)}>{t("Cancel")}</Button>
          <Button variant="contained" onClick={confirmAdd} disabled={!canConfirmAdd}>
            {t("Confirm")}
          </Button>
        </DialogActions>
      </Dialog>

      <Dialog open={moveDialogOpen} onClose={() => setMoveDialogOpen(false)} maxWidth="xs" fullWidth>
        <DialogTitle>{t("Move to order")}</DialogTitle>
        <DialogContent>
          <Stack spacing={1.5} sx={{ mt: 1 }}>
            <TextField
              size="small"
              label={t("Target order")}
              type="number"
              value={moveToOrder}
              onChange={(e) => {
                const v = e.target.value;
                if (v === "") return setMoveToOrder("");
                const n = Number(v);
                if (!Number.isFinite(n)) return;
                setMoveToOrder(n);
              }}
              inputProps={{ min: 1 }}
              onKeyDown={(e) => {
                if (e.key === "Enter") confirmMoveDialog();
              }}
            />
            <RadioGroup
              row
              value={movePlacement}
              onChange={(e) => setMovePlacement(e.target.value as "before" | "after")}
            >
              <FormControlLabel value="before" control={<Radio size="small" />} label={t("In front of")} />
              <FormControlLabel value="after" control={<Radio size="small" />} label={t("Behind")} />
            </RadioGroup>
            <Typography variant="body2" sx={{ color: "text.secondary" }}>
              {t("This will move the item to exact order")}
            </Typography>
          </Stack>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setMoveDialogOpen(false)}>{t("Cancel")}</Button>
          <Button variant="contained" onClick={confirmMoveDialog}>
            {t("Confirm")}
          </Button>
        </DialogActions>
      </Dialog>
    </Box>
  );
}

