import { useState, useRef, useEffect } from "react";
import { useSearchParams } from "react-router-dom";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { Files, User, Users, Folder, Plus, Settings2, Check, X } from "lucide-react";
import {
  listCategories,
  createCategory,
  getMyGroups,
  type CategoryOut,
  ApiError,
} from "@/api/client";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";
import ManageCategoriesDialog from "@/components/ManageCategoriesDialog";

// PascalCase-with-dashes naming convention
const NAME_RE = /^[A-Z][a-zA-Z0-9]*(-[A-Z][a-zA-Z0-9]*)*$/;

export default function SourcePanel() {
  const [searchParams, setSearchParams] = useSearchParams();
  const queryClient = useQueryClient();
  const currentView = searchParams.get("view") ?? "all";
  const currentCategoryId = searchParams.get("category_id");

  const [catSearch, setCatSearch] = useState("");
  const [addingCat, setAddingCat] = useState(false);
  const [newCatName, setNewCatName] = useState("");
  const [newCatGroupId, setNewCatGroupId] = useState<string>("");
  const [nameError, setNameError] = useState<string | null>(null);
  const [manageOpen, setManageOpen] = useState(false);
  const addInputRef = useRef<HTMLInputElement>(null);

  const { data: categories = [] } = useQuery({
    queryKey: ["categories"],
    queryFn: listCategories,
  });

  const { data: myGroups = [] } = useQuery({
    queryKey: ["my-groups"],
    queryFn: getMyGroups,
  });

  const createMut = useMutation({
    mutationFn: ({ name, groupId }: { name: string; groupId?: string }) =>
      createCategory(name, groupId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["categories"] });
      setNewCatName("");
      setNewCatGroupId("");
      setAddingCat(false);
      setNameError(null);
    },
    onError: (err) => {
      setNameError(err instanceof ApiError ? err.message : "Failed to create category");
    },
  });

  useEffect(() => {
    if (addingCat) addInputRef.current?.focus();
  }, [addingCat]);

  const filteredCats = catSearch
    ? categories.filter((c) => c.name.toLowerCase().includes(catSearch.toLowerCase()))
    : categories;

  // Split by scope for display
  const personalCats = filteredCats.filter((c) => c.scope === "personal");
  const systemCats = filteredCats.filter((c) => c.scope === "system");
  const groupCatMap = new Map<string, { name: string; cats: CategoryOut[] }>();
  for (const cat of filteredCats.filter((c) => c.scope === "group")) {
    if (!cat.group_id) continue;
    if (!groupCatMap.has(cat.group_id)) {
      const grp = myGroups.find((g) => g.id === cat.group_id);
      groupCatMap.set(cat.group_id, { name: grp?.name ?? cat.group_id, cats: [] });
    }
    groupCatMap.get(cat.group_id)!.cats.push(cat);
  }

  function setView(view: string) {
    setSearchParams((prev) => {
      const next = new URLSearchParams(prev);
      next.set("view", view);
      next.delete("category_id");
      next.set("page", "1");
      return next;
    });
  }

  function selectCategory(cat: CategoryOut) {
    setSearchParams((prev) => {
      const next = new URLSearchParams(prev);
      next.delete("view");
      next.set("category_id", cat.id);
      next.set("page", "1");
      return next;
    });
  }

  function handleAddSubmit(e: React.FormEvent) {
    e.preventDefault();
    const name = newCatName.trim();
    if (!name) return;
    if (!NAME_RE.test(name)) {
      setNameError(
        "Must start with a capital letter. Join multiple words with dashes, each capitalised (e.g. Vendor-Invoices)."
      );
      return;
    }
    setNameError(null);
    createMut.mutate({ name, groupId: newCatGroupId || undefined });
  }

  const viewItemClass = (active: boolean) =>
    cn(
      "flex items-center gap-2 w-full px-2 py-1.5 rounded-md text-sm transition-colors",
      active
        ? "bg-primary/10 text-primary font-medium"
        : "text-muted hover:bg-muted/20 hover:text-foreground"
    );

  const catItemClass = (active: boolean) =>
    cn(
      "flex items-center gap-2 w-full px-2 py-1 rounded-md text-sm transition-colors",
      active
        ? "bg-primary/10 text-primary font-medium"
        : "text-muted hover:bg-muted/20 hover:text-foreground"
    );

  function renderCatSection(label: string, cats: CategoryOut[]) {
    if (cats.length === 0) return null;
    return (
      <div className="mb-1">
        <p className="text-[10px] font-semibold text-muted uppercase tracking-wider px-2 pt-1.5 pb-0.5">
          {label}
        </p>
        {cats.map((cat) => (
          <button
            key={cat.id}
            className={catItemClass(currentCategoryId === cat.id)}
            onClick={() => selectCategory(cat)}
          >
            <Folder className="h-3.5 w-3.5 shrink-0" />
            <span className="truncate">{cat.name}</span>
          </button>
        ))}
      </div>
    );
  }

  const hasSections =
    personalCats.length > 0 ||
    systemCats.length > 0 ||
    groupCatMap.size > 0;

  return (
    <>
      <aside className="w-56 flex flex-col border-r border-border bg-surface shrink-0 h-screen">
        {/* Views */}
        <div className="p-3 border-b border-border">
          <p className="text-xs font-semibold text-muted uppercase tracking-wider mb-1.5 px-1">
            Views
          </p>
          <button
            className={viewItemClass(!currentCategoryId && (currentView === "all" || !currentView))}
            onClick={() => setView("all")}
          >
            <Files className="h-4 w-4 shrink-0" />
            All Documents
          </button>
          <button
            className={viewItemClass(!currentCategoryId && currentView === "mine")}
            onClick={() => setView("mine")}
          >
            <User className="h-4 w-4 shrink-0" />
            Mine
          </button>
          <button
            className={viewItemClass(!currentCategoryId && currentView === "shared")}
            onClick={() => setView("shared")}
          >
            <Users className="h-4 w-4 shrink-0" />
            Shared with me
          </button>
        </div>

        {/* Categories */}
        <div className="flex-1 flex flex-col min-h-0 p-3">
          <div className="flex items-center justify-between mb-1.5 px-1">
            <p className="text-xs font-semibold text-muted uppercase tracking-wider">
              Categories
            </p>
            <button
              onClick={() => setManageOpen(true)}
              className="text-muted hover:text-foreground transition-colors"
              title="Manage categories"
            >
              <Settings2 className="h-3.5 w-3.5" />
            </button>
          </div>

          {categories.length > 4 && (
            <Input
              placeholder="Search…"
              value={catSearch}
              onChange={(e) => setCatSearch(e.target.value)}
              className="h-7 text-xs mb-2"
            />
          )}

          <div className="flex-1 overflow-y-auto min-h-0">
            {renderCatSection("Mine", personalCats)}
            {Array.from(groupCatMap.entries()).map(([, { name, cats }]) =>
              renderCatSection(name, cats)
            )}
            {renderCatSection("System", systemCats)}
            {!hasSections && catSearch && (
              <p className="text-xs text-muted px-2 py-1">No categories match</p>
            )}
            {categories.length === 0 && !catSearch && (
              <p className="text-xs text-muted px-2 py-1">No categories yet</p>
            )}
          </div>

          {/* Add new category */}
          <div className="pt-2 border-t border-border mt-2">
            {addingCat ? (
              <form onSubmit={handleAddSubmit} className="flex flex-col gap-1">
                <div className="flex items-center gap-1">
                  <Input
                    ref={addInputRef}
                    value={newCatName}
                    onChange={(e) => { setNewCatName(e.target.value); setNameError(null); }}
                    placeholder="Vendor-Invoices"
                    className="h-7 text-xs flex-1"
                    disabled={createMut.isPending}
                  />
                  <button
                    type="submit"
                    disabled={!newCatName.trim() || createMut.isPending}
                    className="text-primary hover:text-primary/80 disabled:opacity-50"
                  >
                    <Check className="h-4 w-4" />
                  </button>
                  <button
                    type="button"
                    onClick={() => {
                      setAddingCat(false);
                      setNewCatName("");
                      setNewCatGroupId("");
                      setNameError(null);
                    }}
                    className="text-muted hover:text-foreground"
                  >
                    <X className="h-4 w-4" />
                  </button>
                </div>
                {myGroups.length > 0 && (
                  <select
                    value={newCatGroupId}
                    onChange={(e) => setNewCatGroupId(e.target.value)}
                    className="h-7 text-xs rounded border border-border bg-surface text-foreground px-1"
                    disabled={createMut.isPending}
                  >
                    <option value="">Personal</option>
                    {myGroups.map((g) => (
                      <option key={g.id} value={g.id}>{g.name}</option>
                    ))}
                  </select>
                )}
                {nameError && (
                  <p className="text-[10px] text-red-500 leading-tight">{nameError}</p>
                )}
              </form>
            ) : (
              <button
                onClick={() => setAddingCat(true)}
                className="flex items-center gap-1.5 text-xs text-muted hover:text-foreground transition-colors w-full px-2 py-1"
              >
                <Plus className="h-3.5 w-3.5" />
                New category
              </button>
            )}
          </div>
        </div>
      </aside>

      {manageOpen && (
        <ManageCategoriesDialog onClose={() => setManageOpen(false)} />
      )}
    </>
  );
}
