import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "../ui/table";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "../ui/select";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "../ui/dialog";
import { Label } from "../ui/label";
import { Switch } from "../ui/switch";
import { Badge } from "../ui/badge";
import { Plus, Edit, MoreHorizontal, X, Trash2 } from "lucide-react";
import { toast } from "sonner";
import { skipCountForPage } from "../../lib/paginationQuery";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "../ui/pagination";
import {
  getLabelMultipleOptions,
  getLabelMultipleOption,
  createLabelMultipleOption,
  updateLabelMultipleOption,
  deleteLabelMultipleOption,
} from "../../services/labelMultipleOptionService";
import { getLabels } from "../../services/labelService";
import { getLocations } from "../../services/locationService";
import { getGroups } from "../../services/groupService";
import { getPartners } from "../../services/partnerService";
import {
  buildEntityScopeSaveFromForm,
  hydrateCategoryScopeFromLocationIds,
  hydrateEntityScopeFromDto,
} from "../../lib/categoryScopeForm";
import { CategoryScopeFields } from "../shared/category-scope-fields";
import { useCategoryScopeAuth } from "../../hooks/useCategoryScopeAuth";
import type {
  LabelMultipleOptionDto,
  LabelMultipleOptionCreateInput,
  LabelMultipleOptionUpdateInput,
} from "../../types/labelMultipleOption";
import type { LocationDto } from "../../types/location";
import type { GroupListItem } from "../../types/group";
import type { PartnerListItem } from "../../types/partner";
import {
  filterGroupsByCompany,
  filterLocationsByCompanyAndRegion,
  matchesCompanyByLocationIds,
  matchesRegionByLocationIds,
  resolveScopedLocationIdsForToolbar,
} from "../../lib/labelingToolbarScope";
import { cn } from "../ui/utils";

function toDisplay(v: string | null | undefined): string {
  const s = (v ?? "").trim();
  return s ? s : "None";
}

/** 新增时由名称生成编码（界面不再手填 Option Code） */
function optionCodeFromName(name: string): string {
  const slug = name
    .trim()
    .toUpperCase()
    .replace(/[^A-Z0-9]+/g, "_")
    .replace(/^_+|_+$/g, "")
    .slice(0, 40);
  return slug ? `OPT_${slug}` : `OPT_${Date.now()}`;
}

/** 列表行单元格统一字体（与 Label Types / Label Categories 一致） */
const LIST_ROW_CELL = "text-sm font-normal font-sans text-gray-900";
const LIST_ROW_CELL_NOWRAP = `${LIST_ROW_CELL} whitespace-nowrap`;
const LIST_STATUS_BADGE = "!text-sm !font-normal font-sans normal-case border-0";

function collectMultipleOptionIdsFromValue(value: unknown, out: Set<string>): void {
  if (value == null) return;
  if (Array.isArray(value)) {
    for (const v of value) collectMultipleOptionIdsFromValue(v, out);
    return;
  }
  if (typeof value === "object") {
    for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
      if (k === "multipleOptionId" || k === "MultipleOptionId") {
        const id = String(v ?? "").trim();
        if (id) out.add(id);
      }
      collectMultipleOptionIdsFromValue(v, out);
    }
  }
}

async function fetchMultipleOptionIdsInLocations(
  locationIds: string[],
  signal: AbortSignal,
): Promise<Set<string>> {
  const optionIds = new Set<string>();
  for (const lid of locationIds) {
    let page = 1;
    for (;;) {
      const res = await getLabels(
        {
          skipCount: skipCountForPage(page),
          maxResultCount: 500,
          locationId: lid,
        },
        signal,
      );
      for (const lbl of res.items ?? []) {
        collectMultipleOptionIdsFromValue(lbl.labelInfoJson, optionIds);
      }
      if ((res.items?.length ?? 0) < 500) break;
      page += 1;
      if (page > 50) break;
    }
    if (signal.aborted) break;
  }
  return optionIds;
}

function locationsForOptionScope(opt: LabelMultipleOptionDto, catalog: LocationDto[]): LocationDto[] {
  const idSet = new Set((opt.locationIds ?? []).map((x) => String(x).trim()).filter(Boolean));
  if (!idSet.size) return [];
  return catalog.filter((l) => idSet.has(l.id));
}

function optionMatchesCompanyFilter(
  opt: LabelMultipleOptionDto,
  companyFilterId: string,
  catalog: LocationDto[],
  partners: PartnerListItem[],
): boolean {
  const lids = (opt.locationIds ?? []).map((x) => String(x).trim()).filter(Boolean);
  return matchesCompanyByLocationIds(lids, companyFilterId, catalog, partners);
}

function optionMatchesRegionFilter(
  opt: LabelMultipleOptionDto,
  regionFilterId: string,
  catalog: LocationDto[],
  groups: GroupListItem[],
): boolean {
  const lids = (opt.locationIds ?? []).map((x) => String(x).trim()).filter(Boolean);
  return matchesRegionByLocationIds(lids, regionFilterId, catalog, groups);
}

function optionMatchesLocationFilter(opt: LabelMultipleOptionDto, locationFilterId: string): boolean {
  if (locationFilterId === "all") return true;
  const lid = locationFilterId.trim();
  if (!lid) return true;
  const lids = new Set((opt.locationIds ?? []).map((x) => String(x).trim()).filter(Boolean));
  if (!lids.size) return true;
  return lids.has(lid);
}

function labelInfoJsonReferencesOptionId(value: unknown, optionId: string): boolean {
  const ids = new Set<string>();
  collectMultipleOptionIdsFromValue(value, ids);
  return ids.has(optionId);
}

async function fetchLocationIdsForMultipleOption(optionId: string, signal?: AbortSignal): Promise<string[]> {
  const lids: string[] = [];
  let page = 1;
  for (;;) {
    const res = await getLabels(
      {
        skipCount: skipCountForPage(page),
        maxResultCount: 500,
      },
      signal,
    );
    for (const lbl of res.items ?? []) {
      if (!labelInfoJsonReferencesOptionId(lbl.labelInfoJson, optionId)) continue;
      const id = (lbl.locationId ?? "").trim();
      if (id) lids.push(id);
    }
    if ((res.items?.length ?? 0) < 500) break;
    page += 1;
    if (page > 50) break;
  }
  return [...new Set(lids)];
}

async function fetchAllLabelMultipleOptionsMatching(
  keyword: string | undefined,
  state: boolean | undefined,
  signal: AbortSignal,
): Promise<LabelMultipleOptionDto[]> {
  const out: LabelMultipleOptionDto[] = [];
  let page = 1;
  const size = 500;
  for (;;) {
    const res = await getLabelMultipleOptions(
      {
        skipCount: skipCountForPage(page),
        maxResultCount: size,
        keyword,
        state,
      },
      signal,
    );
    const items = res.items ?? [];
    out.push(...items);
    if (items.length < size) break;
    page += 1;
    if (page > 200) break;
  }
  return out;
}

export function MultipleOptionsView() {
  const scopeAuth = useCategoryScopeAuth();
  const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
  const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
  const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
  const [editingOption, setEditingOption] = useState<LabelMultipleOptionDto | null>(null);
  const [deletingOption, setDeletingOption] = useState<LabelMultipleOptionDto | null>(null);
  const [options, setOptions] = useState<LabelMultipleOptionDto[]>([]);
  const [loading, setLoading] = useState(false);
  const [total, setTotal] = useState(0);
  const [refreshSeq, setRefreshSeq] = useState(0);
  const [actionsOpenForId, setActionsOpenForId] = useState<string | null>(null);

  const [keyword, setKeyword] = useState("");
  const [companyFilter, setCompanyFilter] = useState("all");
  const [regionFilter, setRegionFilter] = useState("all");
  const [locationFilter, setLocationFilter] = useState("all");
  const [stateFilter, setStateFilter] = useState<string>("all");

  const [pageIndex, setPageIndex] = useState(1);
  const [pageSize, setPageSize] = useState(10);

  const [locationCatalog, setLocationCatalog] = useState<LocationDto[]>([]);
  const [filterGroups, setFilterGroups] = useState<GroupListItem[]>([]);
  const [filterPartners, setFilterPartners] = useState<PartnerListItem[]>([]);

  const abortRef = useRef<AbortController | null>(null);
  const keywordTimerRef = useRef<number | null>(null);
  const [debouncedKeyword, setDebouncedKeyword] = useState("");

  const companySelectOptions = useMemo(
    () =>
      [...filterPartners]
        .filter((p) => (p.partnerName ?? "").trim())
        .sort((a, b) =>
          (a.partnerName ?? "").localeCompare(b.partnerName ?? "", undefined, { sensitivity: "base" }),
        ),
    [filterPartners],
  );

  const regionSelectOptions = useMemo(() => {
    const list = filterGroupsByCompany(filterGroups, companyFilter);
    const m = new Map<string, GroupListItem>();
    for (const g of list) {
      const id = (g.id ?? "").trim();
      if (id && !m.has(id)) m.set(id, g);
    }
    return Array.from(m.values()).sort((a, b) =>
      (a.groupName ?? "").localeCompare(b.groupName ?? "", undefined, { sensitivity: "base" }),
    );
  }, [filterGroups, companyFilter]);

  const locationsForToolbarFilter = useMemo(
    () =>
      filterLocationsByCompanyAndRegion(
        locationCatalog,
        filterPartners,
        companyFilter,
        regionFilter,
        filterGroups,
      ),
    [locationCatalog, filterPartners, companyFilter, regionFilter, filterGroups],
  );

  useEffect(() => {
    setRegionFilter("all");
    setLocationFilter("all");
  }, [companyFilter]);

  useEffect(() => {
    setLocationFilter("all");
  }, [regionFilter]);

  useEffect(() => {
    if (companyFilter === "all") return;
    if (!companySelectOptions.some((p) => p.id === companyFilter)) setCompanyFilter("all");
  }, [companyFilter, companySelectOptions]);

  useEffect(() => {
    if (regionFilter === "all") return;
    if (!regionSelectOptions.some((g) => g.id === regionFilter)) setRegionFilter("all");
  }, [companyFilter, regionSelectOptions, regionFilter]);

  useEffect(() => {
    if (locationFilter === "all") return;
    const allowed = new Set(locationsForToolbarFilter.map((l) => l.id));
    if (!allowed.has(locationFilter)) setLocationFilter("all");
  }, [locationsForToolbarFilter, locationFilter]);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const out: LocationDto[] = [];
        let locPage = 1;
        const locSize = 500;
        for (;;) {
          const res = await getLocations({
            skipCount: skipCountForPage(locPage),
            maxResultCount: locSize,
          });
          out.push(...(res.items ?? []));
          if (!res.items || res.items.length < locSize) break;
          locPage += 1;
          if (locPage > 200) break;
        }
        const [grpRes, partnerRes] = await Promise.all([
          getGroups({ skipCount: 1, maxResultCount: 500 }),
          getPartners({ skipCount: 1, maxResultCount: 500, state: true }),
        ]);
        if (cancelled) return;
        setLocationCatalog(out);
        setFilterGroups(grpRes.items ?? []);
        setFilterPartners(partnerRes.items ?? []);
      } catch {
        if (!cancelled) {
          setLocationCatalog([]);
          setFilterGroups([]);
          setFilterPartners([]);
        }
      }
    })();
    return () => {
      cancelled = true;
    };
  }, []);

  useEffect(() => {
    if (keywordTimerRef.current) window.clearTimeout(keywordTimerRef.current);
    keywordTimerRef.current = window.setTimeout(() => setDebouncedKeyword(keyword.trim()), 300);
    return () => {
      if (keywordTimerRef.current) window.clearTimeout(keywordTimerRef.current);
    };
  }, [keyword]);

  const totalPages = Math.max(1, Math.ceil(total / pageSize));

  useEffect(() => {
    setPageIndex(1);
  }, [debouncedKeyword, companyFilter, regionFilter, locationFilter, stateFilter, pageSize]);

  useEffect(() => {
    const run = async () => {
      abortRef.current?.abort();
      const ac = new AbortController();
      abortRef.current = ac;

      setLoading(true);
      try {
        const skipCount = skipCountForPage(pageIndex);
        const stateBool = stateFilter === "all" ? undefined : stateFilter === "true";
        const kw = debouncedKeyword || undefined;
        const needsClientFilter =
          companyFilter !== "all" || regionFilter !== "all" || locationFilter !== "all";
        const scopeLocationIds = resolveScopedLocationIdsForToolbar(
          companyFilter,
          regionFilter,
          locationFilter,
          locationCatalog,
          filterGroups,
          filterPartners,
        );
        const canUseServerScope =
          companyFilter === "all" && (regionFilter !== "all" || locationFilter !== "all");

        if (!needsClientFilter) {
          const res = await getLabelMultipleOptions(
            {
              skipCount,
              maxResultCount: pageSize,
              keyword: kw,
              state: stateBool,
            },
            ac.signal,
          );

          setOptions(res.items ?? []);
          setTotal(res.totalCount ?? 0);
        } else if (canUseServerScope) {
          const res = await getLabelMultipleOptions(
            {
              skipCount,
              maxResultCount: pageSize,
              keyword: kw,
              state: stateBool,
              groupId: regionFilter !== "all" ? regionFilter : undefined,
              locationId: locationFilter !== "all" ? locationFilter : undefined,
            },
            ac.signal,
          );

          setOptions(res.items ?? []);
          setTotal(res.totalCount ?? 0);
        } else {
          const scopedOptionIds = scopeLocationIds?.length
            ? await fetchMultipleOptionIdsInLocations(scopeLocationIds, ac.signal)
            : new Set<string>();
          const all = await fetchAllLabelMultipleOptionsMatching(kw, stateBool, ac.signal);
          const filtered = all.filter((opt) => {
            const hasScope = (opt.locationIds ?? []).some((x) => String(x).trim());
            if (hasScope) {
              return (
                optionMatchesCompanyFilter(opt, companyFilter, locationCatalog, filterPartners) &&
                optionMatchesRegionFilter(opt, regionFilter, locationCatalog, filterGroups) &&
                optionMatchesLocationFilter(opt, locationFilter)
              );
            }
            return scopedOptionIds.has(opt.id);
          });
          setTotal(filtered.length);
          const start = (pageIndex - 1) * pageSize;
          setOptions(filtered.slice(start, start + pageSize));
        }
      } catch (e: any) {
        if (e?.name === "AbortError") return;
        toast.error("Failed to load multiple options.", {
          description: e?.message ? String(e.message) : "Please try again.",
        });
        setOptions([]);
        setTotal(0);
      } finally {
        setLoading(false);
      }
    };

    run();
    return () => abortRef.current?.abort();
  }, [
    debouncedKeyword,
    companyFilter,
    regionFilter,
    locationFilter,
    stateFilter,
    pageIndex,
    pageSize,
    refreshSeq,
    locationCatalog,
    filterGroups,
    filterPartners,
  ]);

  const refreshList = () => setRefreshSeq((x) => x + 1);

  const openEdit = (opt: LabelMultipleOptionDto) => {
    setActionsOpenForId(null);
    setEditingOption(opt);
    setIsEditDialogOpen(true);
  };

  const openDelete = (opt: LabelMultipleOptionDto) => {
    setActionsOpenForId(null);
    setDeletingOption(opt);
    setIsDeleteDialogOpen(true);
  };

  return (
    <div className="h-full flex flex-col">
      <div className="pb-4">
        <div className="flex flex-col gap-4">
          <div className="flex flex-nowrap items-center gap-3">
            <Input
              placeholder="Search"
              value={keyword}
              onChange={(e) => setKeyword(e.target.value)}
              style={{ height: 40, boxSizing: 'border-box' }}
              className="bg-white border border-gray-300 rounded-md w-40 shrink-0 placeholder:text-gray-500"
            />
            {scopeAuth.requireCompanySelection ? (
              <Select value={companyFilter} onValueChange={setCompanyFilter}>
                <SelectTrigger
                  className="bg-white border border-gray-300 rounded-md w-[150px] shrink-0"
                  style={{ height: 40, boxSizing: "border-box" }}
                >
                  <SelectValue placeholder="Company" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="all">All Companies</SelectItem>
                  {companySelectOptions.map((p) => (
                    <SelectItem key={p.id} value={p.id}>
                      {toDisplay(p.partnerName)}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            ) : null}
            <Select value={regionFilter} onValueChange={setRegionFilter}>
              <SelectTrigger
                className="bg-white border border-gray-300 rounded-md w-[150px] shrink-0"
                style={{ height: 40, boxSizing: "border-box" }}
              >
                <SelectValue placeholder="Region" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">All Region</SelectItem>
                {regionSelectOptions.map((g) => (
                  <SelectItem key={g.id} value={g.id}>
                    {toDisplay(g.groupName)}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <Select value={locationFilter} onValueChange={setLocationFilter}>
              <SelectTrigger
                className="bg-white border border-gray-300 rounded-md w-[170px] shrink-0"
                style={{ height: 40, boxSizing: "border-box" }}
              >
                <SelectValue placeholder="Location" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">All Locations</SelectItem>
                {locationsForToolbarFilter.map((loc) => {
                  const code = (loc.locationCode ?? "").trim();
                  const name = (loc.locationName ?? "").trim();
                  const label = code && name ? `${code} - ${name}` : name || code || loc.id;
                  return (
                    <SelectItem key={loc.id} value={loc.id}>
                      {label}
                    </SelectItem>
                  );
                })}
              </SelectContent>
            </Select>
            <Select value={stateFilter} onValueChange={setStateFilter}>
              <SelectTrigger className="bg-white border border-gray-300 rounded-md w-[150px] shrink-0" style={{ height: 40, boxSizing: 'border-box' }}>
                <SelectValue placeholder="Status" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">Status</SelectItem>
                <SelectItem value="true">Active</SelectItem>
                <SelectItem value="false">Inactive</SelectItem>
              </SelectContent>
            </Select>
            <div className="flex-1" />
            <Button
              className="bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-md h-10 px-6 shrink-0"
              onClick={() => setIsCreateDialogOpen(true)}
            >
              New Multiple Option Set <Plus className="ml-1 h-4 w-4" />
            </Button>
          </div>
        </div>
      </div>

      <div className="flex-1 overflow-auto pt-6">
        <div className="rounded-md border bg-white shadow-sm">
          <Table className="font-sans">
            <TableHeader>
              <TableRow className="bg-gray-50 hover:bg-gray-50">
                <TableHead className="text-sm font-semibold font-sans text-gray-900 min-w-[200px]">Multiple Option Set Name</TableHead>
                <TableHead className="text-sm font-semibold font-sans text-gray-900 min-w-[240px]">Contents</TableHead>
                <TableHead className="text-sm font-semibold font-sans text-gray-900 w-[100px]">Status</TableHead>
                <TableHead className="text-sm font-semibold font-sans text-gray-900 w-[130px]">Sequence Order</TableHead>
                <TableHead className="text-sm font-semibold font-sans text-gray-900 min-w-[140px]">Last Edited</TableHead>
                <TableHead className="text-sm font-semibold font-sans text-gray-900 text-center w-[100px]">Actions</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {loading ? (
                <TableRow>
                  <TableCell colSpan={6} className={`text-center ${LIST_ROW_CELL} py-10`}>
                    Loading...
                  </TableCell>
                </TableRow>
              ) : options.length === 0 ? (
                <TableRow>
                  <TableCell colSpan={6} className={`text-center ${LIST_ROW_CELL} py-10`}>
                    No results.
                  </TableCell>
                </TableRow>
              ) : (
                options.map((item) => {
                  const contentsText =
                    item.optionValuesJson && item.optionValuesJson.length > 0
                      ? item.optionValuesJson.join("; ")
                      : "None";
                  return (
                  <TableRow key={item.id} className="hover:bg-gray-50">
                    <TableCell className={LIST_ROW_CELL_NOWRAP}>
                      {toDisplay(item.optionName)}
                    </TableCell>
                    <TableCell className={`${LIST_ROW_CELL} max-w-[360px]`}>
                      <div className="truncate whitespace-nowrap" title={contentsText}>
                        {contentsText}
                      </div>
                    </TableCell>
                    <TableCell className={LIST_ROW_CELL_NOWRAP}>
                      <Badge
                        variant={item.state !== false ? "default" : "secondary"}
                        className={cn(
                          LIST_STATUS_BADGE,
                          item.state !== false ? "bg-green-600" : "bg-gray-400",
                        )}
                      >
                        {item.state !== false ? "active" : "inactive"}
                      </Badge>
                    </TableCell>
                    <TableCell className={LIST_ROW_CELL_NOWRAP}>
                      {item.orderNum != null && Number.isFinite(item.orderNum) ? item.orderNum : "—"}
                    </TableCell>
                    <TableCell className={LIST_ROW_CELL_NOWRAP}>
                      {toDisplay(item.lastEdited)}
                    </TableCell>
                    <TableCell className={`text-center ${LIST_ROW_CELL_NOWRAP}`}>
                      <Popover
                        open={actionsOpenForId === item.id}
                        onOpenChange={(open) => setActionsOpenForId(open ? item.id : null)}
                      >
                        <PopoverTrigger asChild>
                          <Button
                            type="button"
                            variant="ghost"
                            size="icon"
                            className="h-8 w-8"
                            aria-label="Row actions"
                          >
                            <MoreHorizontal className="h-4 w-4 text-gray-500" />
                          </Button>
                        </PopoverTrigger>
                        <PopoverContent align="end" className="w-40 p-1">
                          <Button
                            type="button"
                            variant="ghost"
                            className="w-full justify-start gap-2 h-9 px-2 font-normal"
                            onClick={() => openEdit(item)}
                          >
                            <Edit className="w-4 h-4" />
                            Edit
                          </Button>
                          <Button
                            type="button"
                            variant="ghost"
                            className="w-full justify-start gap-2 h-9 px-2 font-normal text-red-600 hover:text-red-700 hover:bg-red-50"
                            onClick={() => openDelete(item)}
                          >
                            <Trash2 className="w-4 h-4 shrink-0" />
                            Delete
                          </Button>
                        </PopoverContent>
                      </Popover>
                    </TableCell>
                  </TableRow>
                  );
                })
              )}
            </TableBody>
          </Table>
        </div>
      </div>

      <div className="pt-4">
        <div className="flex items-center justify-between text-sm text-gray-600">
          <div>
            Showing {total === 0 ? 0 : (pageIndex - 1) * pageSize + 1}-
            {Math.min(pageIndex * pageSize, total)} of {total}
          </div>
          <div className="flex items-center gap-3">
            <Select value={String(pageSize)} onValueChange={(v) => setPageSize(Number(v))}>
              <SelectTrigger className="w-[110px] h-9 rounded-md border border-gray-300 bg-white text-gray-900">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {[10, 20, 50].map((n) => (
                  <SelectItem key={n} value={String(n)}>
                    {n} / page
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <Pagination className="mx-0 w-auto justify-end">
              <PaginationContent>
                <PaginationItem>
                  <PaginationPrevious
                    href="#"
                    size="default"
                    onClick={(e) => {
                      e.preventDefault();
                      setPageIndex((p) => Math.max(1, p - 1));
                    }}
                    aria-disabled={pageIndex <= 1}
                    className={pageIndex <= 1 ? "pointer-events-none opacity-50" : ""}
                  />
                </PaginationItem>
                <PaginationItem>
                  <PaginationLink
                    href="#"
                    isActive
                    size="default"
                    onClick={(e) => e.preventDefault()}
                  >
                    Page {pageIndex} / {totalPages}
                  </PaginationLink>
                </PaginationItem>
                <PaginationItem>
                  <PaginationNext
                    href="#"
                    size="default"
                    onClick={(e) => {
                      e.preventDefault();
                      setPageIndex((p) => Math.min(totalPages, p + 1));
                    }}
                    aria-disabled={pageIndex >= totalPages}
                    className={pageIndex >= totalPages ? "pointer-events-none opacity-50" : ""}
                  />
                </PaginationItem>
              </PaginationContent>
            </Pagination>
          </div>
        </div>
      </div>

      <CreateMultipleOptionDialog
        open={isCreateDialogOpen}
        locations={locationCatalog}
        partners={filterPartners}
        groups={filterGroups}
        requireCompanySelection={scopeAuth.requireCompanySelection}
        fixedPartnerId={scopeAuth.fixedPartnerId}
        onOpenChange={setIsCreateDialogOpen}
        onCreated={() => {
          setPageIndex(1);
          refreshList();
        }}
      />

      <EditMultipleOptionDialog
        open={isEditDialogOpen}
        option={editingOption}
        locations={locationCatalog}
        partners={filterPartners}
        groups={filterGroups}
        requireCompanySelection={scopeAuth.requireCompanySelection}
        fixedPartnerId={scopeAuth.fixedPartnerId}
        onOpenChange={(open) => {
          setIsEditDialogOpen(open);
          if (!open) setEditingOption(null);
        }}
        onUpdated={refreshList}
      />

      <DeleteMultipleOptionDialog
        open={isDeleteDialogOpen}
        option={deletingOption}
        onOpenChange={(open) => {
          setIsDeleteDialogOpen(open);
          if (!open) setDeletingOption(null);
        }}
        onDeleted={refreshList}
      />
    </div>
  );
}

function CreateMultipleOptionDialog({
  open,
  locations,
  partners,
  groups,
  requireCompanySelection,
  fixedPartnerId,
  onOpenChange,
  onCreated,
}: {
  open: boolean;
  locations: LocationDto[];
  partners: PartnerListItem[];
  groups: GroupListItem[];
  requireCompanySelection: boolean;
  fixedPartnerId: string;
  onOpenChange: (open: boolean) => void;
  onCreated: () => void;
}) {
  const [submitting, setSubmitting] = useState(false);
  const [selectedPartnerId, setSelectedPartnerId] = useState("");
  const [selectedPartnerIds, setSelectedPartnerIds] = useState<string[]>([]);
  const [selectedRegionNames, setSelectedRegionNames] = useState<string[]>([]);
  const [selectedRegionIds, setSelectedRegionIds] = useState<string[]>([]);
  const [selectedLocationIds, setSelectedLocationIds] = useState<string[]>([]);
  const [form, setForm] = useState<LabelMultipleOptionCreateInput>({
    optionName: "",
    optionValuesJson: [],
    state: true,
    orderNum: null,
  });
  const [newValue, setNewValue] = useState("");

  const resetForm = () => {
    setSelectedPartnerId("");
    setSelectedPartnerIds([]);
    setSelectedRegionNames([]);
    setSelectedRegionIds([]);
    setSelectedLocationIds([]);
    setForm({
      optionName: "",
      optionValuesJson: [],
      state: true,
      orderNum: null,
    });
    setNewValue("");
  };

  useEffect(() => {
    if (!open) {
      resetForm();
    }
  }, [open]);

  const addValue = () => {
    const trimmed = newValue.trim();
    if (!trimmed) return;
    if (form.optionValuesJson.includes(trimmed)) {
      toast.error("Duplicate value", {
        description: "This value already exists.",
      });
      return;
    }
    setForm((p) => ({
      ...p,
      optionValuesJson: [...p.optionValuesJson, trimmed],
    }));
    setNewValue("");
  };

  const removeValue = (index: number) => {
    setForm((p) => ({
      ...p,
      optionValuesJson: p.optionValuesJson.filter((_, i) => i !== index),
    }));
  };

  const submit = async () => {
    if (!form.optionName.trim()) {
      toast.error("Validation failed", {
        description: "Option Name is required.",
      });
      return;
    }
    if (form.optionValuesJson.length === 0) {
      toast.error("Validation failed", {
        description: "At least one option value is required.",
      });
      return;
    }
    if (form.orderNum === null || form.orderNum === undefined || !Number.isFinite(form.orderNum)) {
      toast.error("Validation failed", { description: "Order is required." });
      return;
    }

    const scopePayload = buildEntityScopeSaveFromForm({
      requireCompanySelection,
      selectedPartnerId,
      selectedPartnerIds,
      selectedRegionNames,
      selectedRegionIds,
      selectedLocationIds,
      fixedPartnerId,
      locations,
      partners,
      groups,
    });
    if (!scopePayload.ok) {
      toast.error("Validation failed", { description: scopePayload.message });
      return;
    }

    setSubmitting(true);
    try {
      await createLabelMultipleOption({
        ...form,
        optionCode: optionCodeFromName(form.optionName),
        ...scopePayload.body,
      });
      toast.success("Multiple option created.", {
        description: "The multiple option has been created successfully.",
      });
      onOpenChange(false);
      onCreated();
    } catch (e: any) {
      toast.error("Failed to create multiple option.", {
        description: e?.message ? String(e.message) : "Please try again.",
      });
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-[600px]">
        <DialogHeader>
          <DialogTitle>Add New Multiple Option</DialogTitle>
          <DialogDescription>
            Enter the details for the new multiple option.
          </DialogDescription>
        </DialogHeader>

        <div className="grid gap-4 py-4">
          <div className="space-y-2">
            <Label>Option Name *</Label>
            <Input
              placeholder="e.g. Allergens"
              value={form.optionName}
              onChange={(e) => setForm((p) => ({ ...p, optionName: e.target.value }))}
            />
          </div>

          <div className="space-y-2">
            <Label>Option Values *</Label>
            <div className="flex gap-2">
              <Input
                placeholder="Enter a value and press Add"
                value={newValue}
                onChange={(e) => setNewValue(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === "Enter") {
                    e.preventDefault();
                    addValue();
                  }
                }}
              />
              <Button type="button" onClick={addValue} variant="outline">
                Add
              </Button>
            </div>
            {form.optionValuesJson.length > 0 && (
              <div className="flex flex-wrap gap-2 mt-2">
                {form.optionValuesJson.map((val, idx) => (
                  <Badge key={idx} variant="secondary" className="flex items-center gap-1">
                    {val}
                    <button
                      type="button"
                      onClick={() => removeValue(idx)}
                      className="ml-1 hover:text-red-600"
                    >
                      <X className="h-3 w-3" />
                    </button>
                  </Badge>
                ))}
              </div>
            )}
          </div>

          <div className="grid grid-cols-2 gap-4">
            <div className="space-y-2">
              <Label>Order *</Label>
              <Input
                type="number"
                placeholder="e.g. 1"
                value={form.orderNum ?? ""}
                onChange={(e) => setForm((p) => ({ ...p, orderNum: e.target.value ? Number(e.target.value) : null }))}
              />
            </div>
            <div className="flex items-center justify-between border border-gray-200 rounded-md px-3 bg-white" style={{ height: 40 }}>
              <div className="text-sm font-medium text-gray-900">Enabled</div>
              <Switch checked={form.state} onCheckedChange={(checked) => setForm((p) => ({ ...p, state: checked }))} />
            </div>
          </div>

          <CategoryScopeFields
            partners={partners}
            groups={groups}
            locations={locations}
            selectedPartnerId={selectedPartnerId}
            onPartnerChange={setSelectedPartnerId}
            selectedPartnerIds={selectedPartnerIds}
            onPartnerIdsChange={setSelectedPartnerIds}
            selectedRegionNames={selectedRegionNames}
            onRegionChange={setSelectedRegionNames}
            selectedRegionIds={selectedRegionIds}
            onRegionIdsChange={setSelectedRegionIds}
            selectedLocationIds={selectedLocationIds}
            onLocationChange={setSelectedLocationIds}
            requireCompanySelection={requireCompanySelection}
            fixedPartnerId={fixedPartnerId}
            templateScopeMode={requireCompanySelection}
            selectedPartnerIds={selectedPartnerIds}
            onPartnerIdsChange={setSelectedPartnerIds}
            selectedRegionIds={selectedRegionIds}
            onRegionIdsChange={setSelectedRegionIds}
          />
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cancel
          </Button>
          <Button disabled={submitting} onClick={submit}>
            {submitting ? "Creating..." : "Create"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

function EditMultipleOptionDialog({
  open,
  option,
  locations,
  partners,
  groups,
  requireCompanySelection,
  fixedPartnerId,
  onOpenChange,
  onUpdated,
}: {
  open: boolean;
  option: LabelMultipleOptionDto | null;
  locations: LocationDto[];
  partners: PartnerListItem[];
  groups: GroupListItem[];
  requireCompanySelection: boolean;
  fixedPartnerId: string;
  onOpenChange: (open: boolean) => void;
  onUpdated: () => void;
}) {
  const [submitting, setSubmitting] = useState(false);
  const [loadingDetail, setLoadingDetail] = useState(false);
  const [selectedPartnerId, setSelectedPartnerId] = useState("");
  const [selectedPartnerIds, setSelectedPartnerIds] = useState<string[]>([]);
  const [selectedRegionNames, setSelectedRegionNames] = useState<string[]>([]);
  const [selectedRegionIds, setSelectedRegionIds] = useState<string[]>([]);
  const [selectedLocationIds, setSelectedLocationIds] = useState<string[]>([]);
  const [form, setForm] = useState<LabelMultipleOptionUpdateInput>({
    optionName: "",
    optionValuesJson: [],
    state: true,
    orderNum: null,
  });
  const [newValue, setNewValue] = useState("");

  useEffect(() => {
    if (!open || !option?.id) return;

    const ac = new AbortController();
    setLoadingDetail(true);

    (async () => {
      try {
        const detail = await getLabelMultipleOption(option.id, ac.signal);
        if (ac.signal.aborted) return;

        setForm({
          optionName: detail.optionName ?? option.optionName ?? "",
          optionValuesJson: detail.optionValuesJson ?? option.optionValuesJson ?? [],
          state: detail.state ?? option.state ?? true,
          orderNum: detail.orderNum ?? option.orderNum ?? null,
        });
        setNewValue("");

        if (requireCompanySelection) {
          const scope = hydrateEntityScopeFromDto(detail, locations, partners, groups);
          setSelectedPartnerIds(scope.partnerIds);
          setSelectedRegionIds(scope.regionIds);
          setSelectedLocationIds(scope.locationIds);
          setSelectedPartnerId("");
          setSelectedRegionNames([]);
          return;
        }

        const lids = (detail.locationIds ?? []).map((x) => String(x).trim()).filter(Boolean);
        if (lids.length > 0) {
          const scope = hydrateCategoryScopeFromLocationIds(lids, locations, partners, groups);
          setSelectedPartnerId(scope.partnerId);
          setSelectedRegionNames(scope.regionNames);
          setSelectedLocationIds(scope.locationIds);
          setSelectedPartnerIds([]);
          setSelectedRegionIds([]);
          return;
        }

        const gids = [...(detail.groupIds ?? []), ...(detail.regionIds ?? [])]
          .map((x) => String(x).trim())
          .filter(Boolean);
        if (gids.length > 0) {
          const matchedGroups = groups.filter((g) => gids.includes(g.id));
          const pid = matchedGroups[0]?.partnerId ?? "";
          const names = [
            ...new Set(matchedGroups.map((g) => (g.groupName ?? "").trim()).filter(Boolean)),
          ];
          setSelectedPartnerId(pid);
          setSelectedRegionNames(names);
          setSelectedLocationIds([]);
          setSelectedPartnerIds([]);
          setSelectedRegionIds([]);
          return;
        }

        const fromLabels = await fetchLocationIdsForMultipleOption(option.id, ac.signal);
        if (ac.signal.aborted) return;
        if (fromLabels.length > 0) {
          if (requireCompanySelection) {
            const scope = hydrateLabelingScopeFromLocationIds(fromLabels, locations, partners, groups);
            setSelectedPartnerIds(scope.partnerIds);
            setSelectedRegionIds(scope.regionIds);
            setSelectedLocationIds(scope.locationIds);
            setSelectedPartnerId("");
            setSelectedRegionNames([]);
          } else {
            const scope = hydrateCategoryScopeFromLocationIds(fromLabels, locations, partners, groups);
            setSelectedPartnerId(scope.partnerId);
            setSelectedRegionNames(scope.regionNames);
            setSelectedLocationIds(scope.locationIds);
            setSelectedPartnerIds([]);
            setSelectedRegionIds([]);
          }
        } else {
          setSelectedPartnerId("");
          setSelectedPartnerIds([]);
          setSelectedRegionNames([]);
          setSelectedRegionIds([]);
          setSelectedLocationIds([]);
        }
        setSelectedPartnerIds([]);
        setSelectedRegionIds([]);
      } catch {
        if (ac.signal.aborted) return;
        setForm({
          optionName: option.optionName ?? "",
          optionValuesJson: option.optionValuesJson ?? [],
          state: option.state ?? true,
          orderNum: option.orderNum ?? null,
        });
        setSelectedPartnerId("");
        setSelectedPartnerIds([]);
        setSelectedRegionNames([]);
        setSelectedRegionIds([]);
        setSelectedLocationIds([]);
        setNewValue("");
      } finally {
        if (!ac.signal.aborted) setLoadingDetail(false);
      }
    })();

    return () => ac.abort();
  }, [open, option, locations, partners, groups, requireCompanySelection]);

  const addValue = () => {
    const trimmed = newValue.trim();
    if (!trimmed) return;
    if (form.optionValuesJson.includes(trimmed)) {
      toast.error("Duplicate value", {
        description: "This value already exists.",
      });
      return;
    }
    setForm((p) => ({
      ...p,
      optionValuesJson: [...p.optionValuesJson, trimmed],
    }));
    setNewValue("");
  };

  const removeValue = (index: number) => {
    setForm((p) => ({
      ...p,
      optionValuesJson: p.optionValuesJson.filter((_, i) => i !== index),
    }));
  };

  const submit = async () => {
    if (!option?.id) return;
    if (!form.optionName.trim()) {
      toast.error("Validation failed", {
        description: "Option Name is required.",
      });
      return;
    }
    if (form.optionValuesJson.length === 0) {
      toast.error("Validation failed", {
        description: "At least one option value is required.",
      });
      return;
    }
    if (form.orderNum === null || form.orderNum === undefined || !Number.isFinite(form.orderNum)) {
      toast.error("Validation failed", { description: "Order is required." });
      return;
    }

    const scopePayload = buildEntityScopeSaveFromForm({
      requireCompanySelection,
      selectedPartnerId,
      selectedPartnerIds,
      selectedRegionNames,
      selectedRegionIds,
      selectedLocationIds,
      fixedPartnerId,
      locations,
      partners,
      groups,
    });
    if (!scopePayload.ok) {
      toast.error("Validation failed", { description: scopePayload.message });
      return;
    }

    setSubmitting(true);
    try {
      await updateLabelMultipleOption(option.id, {
        ...form,
        optionCode: option.optionCode ?? "",
        ...scopePayload.body,
      });
      toast.success("Multiple option updated.", {
        description: "The multiple option has been updated successfully.",
      });
      onOpenChange(false);
      onUpdated();
    } catch (e: any) {
      toast.error("Failed to update multiple option.", {
        description: e?.message ? String(e.message) : "Please try again.",
      });
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-[600px]">
        <DialogHeader>
          <DialogTitle>Edit Multiple Option</DialogTitle>
          <DialogDescription>
            Update the multiple option details.
          </DialogDescription>
        </DialogHeader>

        <div className="grid gap-4 py-4">
          <div className="space-y-2">
            <Label>Option Name *</Label>
            <Input
              placeholder="e.g. Allergens"
              value={form.optionName}
              onChange={(e) => setForm((p) => ({ ...p, optionName: e.target.value }))}
            />
          </div>

          <div className="space-y-2">
            <Label>Option Values *</Label>
            <div className="flex gap-2">
              <Input
                placeholder="Enter a value and press Add"
                value={newValue}
                onChange={(e) => setNewValue(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === "Enter") {
                    e.preventDefault();
                    addValue();
                  }
                }}
              />
              <Button type="button" onClick={addValue} variant="outline">
                Add
              </Button>
            </div>
            {form.optionValuesJson.length > 0 && (
              <div className="flex flex-wrap gap-2 mt-2">
                {form.optionValuesJson.map((val, idx) => (
                  <Badge key={idx} variant="secondary" className="flex items-center gap-1">
                    {val}
                    <button
                      type="button"
                      onClick={() => removeValue(idx)}
                      className="ml-1 hover:text-red-600"
                    >
                      <X className="h-3 w-3" />
                    </button>
                  </Badge>
                ))}
              </div>
            )}
          </div>

          <div className="grid grid-cols-2 gap-4">
            <div className="space-y-2">
              <Label>Order *</Label>
              <Input
                type="number"
                placeholder="e.g. 1"
                value={form.orderNum ?? ""}
                onChange={(e) => setForm((p) => ({ ...p, orderNum: e.target.value ? Number(e.target.value) : null }))}
              />
            </div>
            <div className="flex items-center justify-between border border-gray-200 rounded-md px-3 bg-white" style={{ height: 40 }}>
              <div className="text-sm font-medium text-gray-900">Enabled</div>
              <Switch checked={form.state} onCheckedChange={(checked) => setForm((p) => ({ ...p, state: checked }))} />
            </div>
          </div>

          {loadingDetail ? (
            <p className="text-sm text-gray-500">Loading company, region and location…</p>
          ) : (
            <CategoryScopeFields
              partners={partners}
              groups={groups}
              locations={locations}
              selectedPartnerId={selectedPartnerId}
              onPartnerChange={setSelectedPartnerId}
              selectedPartnerIds={selectedPartnerIds}
              onPartnerIdsChange={setSelectedPartnerIds}
              selectedRegionNames={selectedRegionNames}
              onRegionChange={setSelectedRegionNames}
              selectedRegionIds={selectedRegionIds}
              onRegionIdsChange={setSelectedRegionIds}
              selectedLocationIds={selectedLocationIds}
              onLocationChange={setSelectedLocationIds}
              requireCompanySelection={requireCompanySelection}
              fixedPartnerId={fixedPartnerId}
              templateScopeMode={requireCompanySelection}
              selectedPartnerIds={selectedPartnerIds}
              onPartnerIdsChange={setSelectedPartnerIds}
              selectedRegionIds={selectedRegionIds}
              onRegionIdsChange={setSelectedRegionIds}
            />
          )}
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={() => onOpenChange(false)}>
            Cancel
          </Button>
          <Button disabled={submitting || loadingDetail} onClick={submit}>
            {submitting ? "Updating..." : "Update"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

function DeleteMultipleOptionDialog({
  open,
  option,
  onOpenChange,
  onDeleted,
}: {
  open: boolean;
  option: LabelMultipleOptionDto | null;
  onOpenChange: (open: boolean) => void;
  onDeleted: () => void;
}) {
  const [submitting, setSubmitting] = useState(false);

  const name = useMemo(() => {
    const n = (option?.optionName ?? "").trim();
    return n || option?.optionCode || "this option";
  }, [option]);

  const submit = async () => {
    if (!option?.id) return;
    setSubmitting(true);
    try {
      await deleteLabelMultipleOption(option.id);
      toast.success("Multiple option deleted.", {
        description: "The multiple option has been removed successfully.",
      });
      onOpenChange(false);
      onDeleted();
    } catch (e: any) {
      toast.error("Failed to delete multiple option.", {
        description: e?.message ? String(e.message) : "Please try again.",
      });
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-none" style={{ width: "30%" }}>
        <DialogHeader>
          <DialogTitle>Delete Multiple Option</DialogTitle>
          <DialogDescription>This action cannot be undone.</DialogDescription>
        </DialogHeader>

        <div className="text-sm text-gray-700">
          Are you sure you want to delete <span className="font-medium">{name}</span>?
        </div>

        <DialogFooter className="flex-row flex-wrap justify-end">
          <Button className="min-w-24" variant="outline" onClick={() => onOpenChange(false)}>
            Cancel
          </Button>
          <Button
            className="min-w-24 gap-2"
            variant="destructive"
            disabled={submitting}
            onClick={submit}
          >
            <Trash2 className="h-4 w-4 shrink-0" />
            {submitting ? "Deleting..." : "Delete"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
