import React, { useEffect, useMemo, useRef, useState } from "react";
import { Edit, MoreHorizontal, Plus, Trash2 } 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 {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "../ui/dialog";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "../ui/table";
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "../ui/pagination";

import { createMenu, deleteMenu, getMenus, updateMenu } from "../../services/menuService";
import type { MenuCreateInput, MenuDto } from "../../types/menu";

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

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

function formatDateTime(v: string | null | undefined): string {
  const s = (v ?? "").trim();
  if (!s) return "N/A";
  const d = new Date(s);
  if (Number.isNaN(d.getTime())) return s;
  return d.toLocaleString();
}

export function MenuManagementView() {
  const [menus, setMenus] = useState<MenuDto[]>([]);
  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 keywordTimerRef = useRef<number | null>(null);
  const [debouncedKeyword, setDebouncedKeyword] = useState("");

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

  const [isCreateOpen, setIsCreateOpen] = useState(false);
  const [isEditOpen, setIsEditOpen] = useState(false);
  const [isDeleteOpen, setIsDeleteOpen] = useState(false);
  const [editing, setEditing] = useState<MenuDto | null>(null);
  const [deleting, setDeleting] = useState<MenuDto | 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(() => {
    setPageIndex(1);
  }, [debouncedKeyword]);

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

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

      setLoading(true);
      try {
        const skipCount = (pageIndex - 1) * pageSize;
        const res = await getMenus(
          {
            skipCount,
            maxResultCount: pageSize,
            keyword: debouncedKeyword || undefined,
          },
          ac.signal,
        );
        setMenus(res.items ?? []);
        setTotal(res.totalCount ?? 0);
      } catch (e: any) {
        if (e?.name === "AbortError") return;
        toast.error("Failed to load menus.", {
          description: e?.message ? String(e.message) : "Please try again.",
        });
        setMenus([]);
        setTotal(0);
      } finally {
        setLoading(false);
      }
    };

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

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

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

  const openDelete = (m: MenuDto) => {
    setActionsOpenForId(null);
    setDeleting(m);
    setIsDeleteOpen(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="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>
      </div>

      <div className="flex-1 bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
        <div className="h-full 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">Name</TableHead>
                <TableHead className="font-semibold text-gray-900">Path</TableHead>
                <TableHead className="font-semibold text-gray-900">Icon</TableHead>
                <TableHead className="font-semibold text-gray-900">Order</TableHead>
                <TableHead className="font-semibold text-gray-900">Parent ID</TableHead>
                <TableHead className="font-semibold text-gray-900">Enabled</TableHead>
                <TableHead className="font-semibold text-gray-900">Created At</TableHead>
                <TableHead className="font-semibold text-gray-900 w-16">Actions</TableHead>
              </TableRow>
            </TableHeader>

            <TableBody>
              {menus.length === 0 ? (
                <TableRow>
                  <TableCell colSpan={8} className="text-center py-10 text-gray-500">
                    {loading ? "Loading..." : "No data"}
                  </TableCell>
                </TableRow>
              ) : (
                menus.map((m) => (
                  <TableRow key={m.id} className="hover:bg-gray-50">
                    <TableCell className="font-medium text-gray-900">{toDisplay(m.name)}</TableCell>
                    <TableCell className="text-gray-700">{toDisplay(m.path)}</TableCell>
                    <TableCell className="text-gray-700">{toDisplay(m.icon)}</TableCell>
                    <TableCell className="text-gray-700">{m.order ?? "N/A"}</TableCell>
                    <TableCell className="text-gray-700">{toDisplay(m.parentId)}</TableCell>
                    <TableCell className="text-gray-700">{m.isEnabled ? "Yes" : "No"}</TableCell>
                    <TableCell className="text-gray-700">{formatDateTime(m.createdAt)}</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">
                            <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 className="px-4 py-3 border-t border-gray-200 bg-white flex items-center justify-between">
          <div className="text-sm text-gray-600">
            {total === 0 ? "0 results" : `${total} results`}
          </div>

          <Pagination>
            <PaginationContent>
              <PaginationItem>
                <PaginationPrevious
                  href="#"
                  onClick={(e) => {
                    e.preventDefault();
                    setPageIndex((p) => Math.max(1, p - 1));
                  }}
                />
              </PaginationItem>
              {Array.from({ length: Math.min(5, totalPages) }, (_, i) => {
                const page = i + 1;
                return (
                  <PaginationItem key={page}>
                    <PaginationLink
                      href="#"
                      isActive={pageIndex === page}
                      onClick={(e) => {
                        e.preventDefault();
                        setPageIndex(page);
                      }}
                    >
                      {page}
                    </PaginationLink>
                  </PaginationItem>
                );
              })}
              <PaginationItem>
                <PaginationNext
                  href="#"
                  onClick={(e) => {
                    e.preventDefault();
                    setPageIndex((p) => Math.min(totalPages, p + 1));
                  }}
                />
              </PaginationItem>
            </PaginationContent>
          </Pagination>
        </div>
      </div>

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

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

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

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

  const [name, setName] = useState("");
  const [path, setPath] = useState("");
  const [icon, setIcon] = useState("");
  const [order, setOrder] = useState("");
  const [parentId, setParentId] = useState("");
  const [isEnabled, setIsEnabled] = useState(true);

  useEffect(() => {
    if (!open) return;
    setName(menu?.name ?? "");
    setPath(menu?.path ?? "");
    setIcon(menu?.icon ?? "");
    setOrder(menu?.order === null || menu?.order === undefined ? "" : String(menu.order));
    setParentId(menu?.parentId ?? "");
    setIsEnabled(menu?.isEnabled ?? true);
  }, [open, menu]);

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

  const submit = async () => {
    if (!canSubmit) {
      toast.error("Please fill in required fields.", {
        description: "Name and Path are required.",
      });
      return;
    }
    setSubmitting(true);
    try {
      const payload: MenuCreateInput = {
        name: name.trim(),
        path: path.trim(),
        icon: icon.trim() ? icon.trim() : null,
        order: toNumberOrNull(order),
        parentId: parentId.trim() ? parentId.trim() : null,
        isEnabled,
      };

      if (isEdit) {
        if (!menu?.id) throw new Error("Missing menu id.");
        await updateMenu(menu.id, payload);
        toast.success("Menu updated.", { description: "Changes have been saved successfully." });
      } else {
        await createMenu(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: "60%" }}>
        <DialogHeader>
          <DialogTitle>{isEdit ? "Edit Menu" : "New Menu"}</DialogTitle>
          <DialogDescription>
            {isEdit ? "Update menu fields and save changes." : "Fill out the form to create a new menu."}
          </DialogDescription>
        </DialogHeader>

        <div className="grid grid-cols-2 gap-6 py-2">
          <div className="space-y-2">
            <Label htmlFor="menu-name">Name</Label>
            <Input id="menu-name" value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Dashboard" />
          </div>

          <div className="space-y-2">
            <Label htmlFor="menu-path">Path</Label>
            <Input id="menu-path" value={path} onChange={(e) => setPath(e.target.value)} placeholder="e.g. /dashboard" />
          </div>

          <div className="space-y-2">
            <Label htmlFor="menu-icon">Icon</Label>
            <Input id="menu-icon" value={icon} onChange={(e) => setIcon(e.target.value)} placeholder="e.g. LayoutDashboard" />
          </div>

          <div className="space-y-2">
            <Label htmlFor="menu-order">Order</Label>
            <Input id="menu-order" value={order} onChange={(e) => setOrder(e.target.value)} placeholder="e.g. 10" />
          </div>

          <div className="space-y-2">
            <Label htmlFor="menu-parentId">Parent ID</Label>
            <Input id="menu-parentId" value={parentId} onChange={(e) => setParentId(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, boxSizing: "border-box" }}>
            <div className="text-sm font-medium text-gray-900">Enabled</div>
            <Switch checked={isEnabled} onCheckedChange={setIsEnabled} />
          </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 DeleteMenuDialog({
  open,
  menu,
  onOpenChange,
  onDeleted,
}: {
  open: boolean;
  menu: MenuDto | null;
  onOpenChange: (open: boolean) => void;
  onDeleted: () => void;
}) {
  const [submitting, setSubmitting] = useState(false);

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

  const submit = async () => {
    if (!menu?.id) return;
    setSubmitting(true);
    try {
      await deleteMenu(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 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>
  );
}

