import React, { useEffect, useMemo, useRef, useState } from "react";
import {
  Edit,
  FileBox,
  FileText,
  HelpCircle,
  Layers,
  LayoutDashboard,
  MapPin,
  MoreHorizontal,
  Package,
  Plus,
  Settings,
  Tag,
  Trash2,
  Type,
  Users,
} from "lucide-react";
import { toast } from "sonner";

import { Button } from "../ui/button";
import { Input } from "../ui/input";
import { Label } from "../ui/label";
import { Switch } from "../ui/switch";
import { Textarea } from "../ui/textarea";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "../ui/dialog";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "../ui/table";

import {
  createSystemMenu,
  deleteSystemMenu,
  getDirectoryMenusForParentSelect,
  getSystemMenus,
  updateSystemMenu,
} from "../../services/systemMenuService";
import type { SystemMenuDto, SystemMenuUpsertInput } from "../../types/systemMenu";

type IconKey =
  | "Settings"
  | "LayoutDashboard"
  | "Tag"
  | "MapPin"
  | "Users"
  | "Package"
  | "FileText"
  | "HelpCircle"
  | "Layers"
  | "Type"
  | "FileBox";

const ICONS: Record<IconKey, React.ComponentType<{ className?: string }>> = {
  Settings,
  LayoutDashboard,
  Tag,
  MapPin,
  Users,
  Package,
  FileText,
  HelpCircle,
  Layers,
  Type,
  FileBox,
};

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

function toIntOrNull(v: string): number | null {
  const s = v.trim();
  if (!s) return null;
  const n = Number.parseInt(s, 10);
  return Number.isFinite(n) ? n : null;
}

export function SystemMenuView() {
  const [items, setItems] = useState<SystemMenuDto[]>([]);
  const [loading, setLoading] = useState(false);
  const [refreshSeq, setRefreshSeq] = useState(0);
  const [actionsOpenForId, setActionsOpenForId] = useState<string | null>(null);

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

  const [isCreateOpen, setIsCreateOpen] = useState(false);
  const [isEditOpen, setIsEditOpen] = useState(false);
  const [isDeleteOpen, setIsDeleteOpen] = useState(false);
  const [editing, setEditing] = useState<SystemMenuDto | null>(null);
  const [deleting, setDeleting] = useState<SystemMenuDto | null>(null);

  const abortRef = useRef<AbortController | null>(null);

  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]);

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

      setLoading(true);
      try {
        const res = await getSystemMenus(
          {
            // 这里不分页展示：一次性拉大页数据
            skipCount: 1,
            maxResultCount: 5000,
            keyword: debouncedKeyword || undefined,
          },
          ac.signal,
        );
        setItems(res.items ?? []);
      } catch (e: any) {
        if (e?.name === "AbortError") return;
        toast.error("Failed to load system menus.", {
          description: e?.message ? String(e.message) : "Please try again.",
        });
        setItems([]);
      } finally {
        setLoading(false);
      }
    };

    run();
    return () => abortRef.current?.abort();
  }, [debouncedKeyword, refreshSeq]);

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

  const openEdit = (m: SystemMenuDto) => {
    setActionsOpenForId(null);
    setEditing(m);
    setIsEditOpen(true);
  };

  const openDelete = (m: SystemMenuDto) => {
    setActionsOpenForId(null);
    setDeleting(m);
    setIsDeleteOpen(true);
  };

  return (
    <div className="h-full flex flex-col">
      <div className="pb-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="border border-gray-300 rounded-md w-40 shrink-0 bg-white placeholder:text-gray-500"
          />
          <div className="flex-1" />
          <Button className="bg-blue-600 text-white hover:bg-blue-700" onClick={() => setIsCreateOpen(true)}>
            <Plus className="w-4 h-4 mr-2" />
            New Menu
          </Button>
        </div>
      </div>

      {/* flex-col + min-h-0：表格区域滚动，底部分页栏始终可见（避免被 overflow-hidden 裁掉） */}
      <div className="flex-1 flex flex-col min-h-0 bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
        <div className="flex-1 min-h-0 overflow-auto">
          <Table>
            <TableHeader className="bg-gray-50 sticky top-0 z-10">
              <TableRow className="hover:bg-gray-50">
                <TableHead className="font-semibold text-gray-900">Menu Name</TableHead>
                <TableHead className="font-semibold text-gray-900">Route URL</TableHead>
                <TableHead className="font-semibold text-gray-900">Router Name</TableHead>
                <TableHead className="font-semibold text-gray-900">Type</TableHead>
                <TableHead className="font-semibold text-gray-900">Order</TableHead>
                <TableHead className="font-semibold text-gray-900">Visible</TableHead>
                <TableHead className="font-semibold text-gray-900">Enabled</TableHead>
                <TableHead className="font-semibold text-gray-900 w-16 text-right">Actions</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {items.length === 0 ? (
                <TableRow>
                  <TableCell colSpan={8} className="text-center py-10 text-gray-500">
                    {loading ? "Loading..." : "No data"}
                  </TableCell>
                </TableRow>
              ) : (
                items.map((m) => (
                  <TableRow key={m.id} className="hover:bg-gray-50">
                    <TableCell className="font-medium text-gray-900">{toDisplay(m.menuName)}</TableCell>
                    <TableCell className="text-gray-700">{toDisplay(m.routeUrl)}</TableCell>
                    <TableCell className="text-gray-700">{toDisplay(m.routerName)}</TableCell>
                    <TableCell className="text-gray-700">{m.menuType ?? "N/A"}</TableCell>
                    <TableCell className="text-gray-700">{m.orderNum ?? "N/A"}</TableCell>
                    <TableCell className="text-gray-700">{m.isShow ? "Yes" : "No"}</TableCell>
                    <TableCell className="text-gray-700">{m.state ? "Yes" : "No"}</TableCell>
                    <TableCell className="text-right">
                      <Popover
                        open={actionsOpenForId === m.id}
                        onOpenChange={(open) => setActionsOpenForId(open ? m.id : null)}
                      >
                        <PopoverTrigger asChild>
                          <Button variant="ghost" size="icon" className="h-8 w-8" aria-label="Row actions">
                            <MoreHorizontal className="h-4 w-4" />
                          </Button>
                        </PopoverTrigger>
                        <PopoverContent className="w-44 p-2" align="end">
                          <div className="flex flex-col">
                            <Button variant="ghost" className="justify-start" onClick={() => openEdit(m)}>
                              <Edit className="w-4 h-4 mr-2" />
                              Edit
                            </Button>
                            <Button
                              variant="ghost"
                              className="justify-start text-red-600 hover:text-red-700"
                              onClick={() => openDelete(m)}
                            >
                              <Trash2 className="w-4 h-4 mr-2" />
                              Delete
                            </Button>
                          </div>
                        </PopoverContent>
                      </Popover>
                    </TableCell>
                  </TableRow>
                ))
              )}
            </TableBody>
          </Table>
        </div>
      </div>

      <SystemMenuDialog
        mode="create"
        open={isCreateOpen}
        menu={null}
        onOpenChange={setIsCreateOpen}
        onSaved={refreshList}
      />

      <SystemMenuDialog
        mode="edit"
        open={isEditOpen}
        menu={editing}
        onOpenChange={setIsEditOpen}
        onSaved={refreshList}
      />

      <DeleteSystemMenuDialog
        open={isDeleteOpen}
        menu={deleting}
        onOpenChange={setIsDeleteOpen}
        onDeleted={refreshList}
      />
    </div>
  );
}

function SystemMenuDialog({
  mode,
  open,
  menu,
  onOpenChange,
  onSaved,
}: {
  mode: "create" | "edit";
  open: boolean;
  menu: SystemMenuDto | null;
  onOpenChange: (open: boolean) => void;
  onSaved: () => void;
}) {
  const isEdit = mode === "edit";
  const [submitting, setSubmitting] = useState(false);

  // 按图二字段（英文展示）
  const [menuName, setMenuName] = useState("");
  const [routerName, setRouterName] = useState("");
  const [routeUrl, setRouteUrl] = useState("");
  const [menuType, setMenuType] = useState<"directory" | "menu">("menu");
  const [permissionCode, setPermissionCode] = useState("");
  const [parentId, setParentId] = useState("");
  const [parentDirectories, setParentDirectories] = useState<SystemMenuDto[]>([]);
  const [parentDirsLoading, setParentDirsLoading] = useState(false);
  const [menuIcon, setMenuIcon] = useState<IconKey | "">("");
  const [orderNum, setOrderNum] = useState("");
  const [link, setLink] = useState("");
  const [component, setComponent] = useState("");
  const [query, setQuery] = useState("");
  const [remark, setRemark] = useState("");

  const [isCache, setIsCache] = useState(false);
  const [isShow, setIsShow] = useState(true);
  const [state, setState] = useState(true);

  useEffect(() => {
    if (!open) return;
    setSubmitting(false);

    setMenuName(menu?.menuName ?? "");
    setRouterName(menu?.routerName ?? "");
    setRouteUrl(menu?.routeUrl ?? "");
    // menuType: 目录/菜单（默认菜单）
    // 这里按常见约定：0=Directory, 1=Menu；若后端枚举不同，再按 Swagger 调整
    setMenuType(menu?.menuType === 0 ? "directory" : "menu");
    setPermissionCode(menu?.permissionCode ?? "");
    const rawPid = String(menu?.parentId ?? "").trim();
    setParentId(
      !rawPid || rawPid === "00000000-0000-0000-0000-000000000000" ? "" : rawPid,
    );
    setMenuIcon((menu?.menuIcon as IconKey | null) ?? "");
    setOrderNum(menu?.orderNum === null || menu?.orderNum === undefined ? "" : String(menu.orderNum));
    setLink(menu?.link ?? "");
    setComponent(menu?.component ?? "");
    setQuery(menu?.query ?? "");
    setRemark(menu?.remark ?? "");

    setIsCache(!!menu?.isCache);
    setIsShow(menu?.isShow ?? true);
    setState(menu?.state ?? true);
  }, [open, menu]);

  const PARENT_ROOT = "__parent_root__";

  useEffect(() => {
    if (!open) return;
    let cancelled = false;
    setParentDirsLoading(true);
    getDirectoryMenusForParentSelect()
      .then((list) => {
        if (!cancelled) setParentDirectories(list);
      })
      .catch(() => {
        if (!cancelled) setParentDirectories([]);
      })
      .finally(() => {
        if (!cancelled) setParentDirsLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [open]);

  const isRootParentId = (id: string) =>
    !id.trim() || id === "00000000-0000-0000-0000-000000000000";

  const parentSelectOptions = useMemo(() => {
    const dirs = parentDirectories.filter((d) => d.id && d.id !== menu?.id);
    const pid = (parentId || "").trim();
    if (pid && !isRootParentId(pid) && !dirs.some((d) => d.id === pid)) {
      return [
        ...dirs,
        { id: pid, menuName: `(Current parent) ${pid}` } as SystemMenuDto,
      ];
    }
    return dirs;
  }, [parentDirectories, parentId, menu?.id]);

  const parentSelectValue = isRootParentId(parentId) ? PARENT_ROOT : parentId;

  const canSubmit = useMemo(() => {
    return Boolean(menuName.trim() && routeUrl.trim());
  }, [menuName, routeUrl]);

  const submit = async () => {
    if (!canSubmit) {
      toast.error("Please fill in required fields.", {
        description: "Menu Name and Route URL are required.",
      });
      return;
    }

    setSubmitting(true);
    try {
      const payload: SystemMenuUpsertInput = {
        menuName: menuName.trim(),
        routerName: routerName.trim() ? routerName.trim() : null,
        routeUrl: routeUrl.trim(),
        // 0=Directory, 1=Menu
        menuType: menuType === "directory" ? 0 : 1,
        permissionCode: permissionCode.trim() ? permissionCode.trim() : null,
        parentId: isRootParentId(parentId) ? null : parentId.trim(),
        menuIcon: menuIcon ? menuIcon : null,
        orderNum: toIntOrNull(orderNum),
        link: link.trim() ? link.trim() : null,
        component: component.trim() ? component.trim() : null,
        query: query.trim() ? query.trim() : null,
        remark: remark.trim() ? remark.trim() : null,
        isCache,
        isShow,
        state,
      };

      if (isEdit) {
        if (!menu?.id) throw new Error("Missing id.");
        await updateSystemMenu(menu.id, payload);
        toast.success("Menu updated.", { description: "Changes have been saved successfully." });
      } else {
        await createSystemMenu(payload);
        toast.success("Menu created.", { description: "A new menu has been created successfully." });
      }

      onOpenChange(false);
      onSaved();
    } catch (e: any) {
      toast.error(isEdit ? "Failed to update menu." : "Failed to create menu.", {
        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: "70%" }}>
        <DialogHeader>
          <DialogTitle>{isEdit ? "Edit System Menu" : "New System Menu"}</DialogTitle>
          <DialogDescription>
            {isEdit ? "Update system menu fields and save changes." : "Fill out the form to create a new system menu."}
          </DialogDescription>
        </DialogHeader>

        <div className="grid grid-cols-3 gap-6 py-2">
          <div className="space-y-2">
            <Label>Menu Name *</Label>
            <Input value={menuName} onChange={(e) => setMenuName(e.target.value)} placeholder="e.g. Location Manager" />
          </div>
          <div className="space-y-2">
            <Label>Route URL *</Label>
            <Input value={routeUrl} onChange={(e) => setRouteUrl(e.target.value)} placeholder="e.g. /location" />
          </div>
          <div className="space-y-2">
            <Label>Router Name</Label>
            <Input value={routerName} onChange={(e) => setRouterName(e.target.value)} placeholder="e.g. location" />
          </div>

          <div className="space-y-2">
            <Label>Menu Type</Label>
            <Select value={menuType} onValueChange={(v) => setMenuType(v as "directory" | "menu")}>
              <SelectTrigger className="h-10 rounded-md border border-gray-200 bg-white">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="directory">Directory</SelectItem>
                <SelectItem value="menu">Menu</SelectItem>
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-2">
            <Label>Permission Code</Label>
            <Input value={permissionCode} onChange={(e) => setPermissionCode(e.target.value)} placeholder="e.g. sys:menu" />
          </div>
          <div className="space-y-2">
            <Label>Parent</Label>
            <Select
              value={parentSelectValue}
              disabled={parentDirsLoading}
              onValueChange={(v) => setParentId(v === PARENT_ROOT ? "" : v)}
            >
              <SelectTrigger className="h-10 rounded-md border border-gray-200 bg-white">
                <SelectValue placeholder={parentDirsLoading ? "Loading…" : "Select parent directory"} />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value={PARENT_ROOT}>Root (no parent)</SelectItem>
                {parentSelectOptions.map((d) => (
                  <SelectItem key={d.id} value={d.id!}>
                    {d.menuName?.trim() || d.id}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>

          <div className="space-y-2">
            <Label>Menu Icon</Label>
            <Select value={menuIcon || "none"} onValueChange={(v) => setMenuIcon(v === "none" ? "" : (v as IconKey))}>
              <SelectTrigger className="h-10 rounded-md border border-gray-200 bg-white">
                <SelectValue placeholder="Select an icon" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="none">None</SelectItem>
                {(Object.keys(ICONS) as IconKey[]).map((k) => {
                  const Icon = ICONS[k];
                  return (
                    <SelectItem key={k} value={k}>
                      <span className="flex items-center gap-2">
                        <Icon className="h-4 w-4" />
                        {k}
                      </span>
                    </SelectItem>
                  );
                })}
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-2">
            <Label>Order</Label>
            <Input value={orderNum} onChange={(e) => setOrderNum(e.target.value)} placeholder="e.g. 10" />
          </div>
          <div className="space-y-2">
            <Label>Link</Label>
            <Input value={link} onChange={(e) => setLink(e.target.value)} placeholder="Optional" />
          </div>

          <div className="space-y-2">
            <Label>Component</Label>
            <Input value={component} onChange={(e) => setComponent(e.target.value)} placeholder="Optional" />
          </div>
          <div className="space-y-2">
            <Label>Query</Label>
            <Input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Optional" />
          </div>
          <div className="space-y-2">
            <Label>Remark</Label>
            <Textarea value={remark} onChange={(e) => setRemark(e.target.value)} placeholder="Optional" />
          </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">Cache</div>
            <Switch checked={isCache} onCheckedChange={setIsCache} />
          </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">Visible</div>
            <Switch checked={isShow} onCheckedChange={setIsShow} />
          </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={state} onCheckedChange={setState} />
          </div>
        </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 bg-blue-600 text-white hover:bg-blue-700" disabled={submitting} onClick={submit}>
            {submitting ? "Saving..." : isEdit ? "Save Changes" : "Create"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

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

  const name = useMemo(() => {
    const n = (menu?.menuName ?? "").trim();
    const p = (menu?.routeUrl ?? "").trim();
    if (n && p) return `${n} (${p})`;
    return n || p || "this menu";
  }, [menu?.menuName, menu?.routeUrl]);

  const submit = async () => {
    if (!menu?.id) return;
    setSubmitting(true);
    try {
      await deleteSystemMenu(menu.id);
      toast.success("Menu deleted.", { description: "The menu has been removed successfully." });
      onOpenChange(false);
      onDeleted();
    } catch (e: any) {
      toast.error("Failed to delete menu.", {
        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 System Menu</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" variant="destructive" disabled={submitting} onClick={submit}>
            {submitting ? "Deleting..." : "Delete"}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

