import * as api from "@client/api";
import type { KeywordSet } from "@shared/types";
import { Loader2, Plus, Trash2 } from "lucide-react";
import type React from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";

type KeywordSetPickerProps = {
  disabled?: boolean;
  onActiveSetChange: (set: KeywordSet) => void;
};

export const KeywordSetPicker: React.FC<KeywordSetPickerProps> = ({
  disabled = false,
  onActiveSetChange,
}) => {
  const [sets, setSets] = useState<KeywordSet[]>([]);
  const [loading, setLoading] = useState(false);
  const [creating, setCreating] = useState(false);
  const [newSetName, setNewSetName] = useState("");
  const [showCreate, setShowCreate] = useState(false);
  const onActiveSetChangeRef = useRef(onActiveSetChange);
  const lastNotifiedIdRef = useRef<string | null>(null);

  onActiveSetChangeRef.current = onActiveSetChange;

  const notifyActiveSet = useCallback((set: KeywordSet) => {
    if (lastNotifiedIdRef.current === set.id) return;
    lastNotifiedIdRef.current = set.id;
    onActiveSetChangeRef.current(set);
  }, []);

  const loadSets = useCallback(async () => {
    setLoading(true);
    try {
      const list = await api.listKeywordSets();
      setSets(list);
      const active = list.find((s) => s.isActive) ?? list[0];
      if (active) notifyActiveSet(active);
    } catch {
      toast.error("Failed to load keyword sets");
    } finally {
      setLoading(false);
    }
  }, [notifyActiveSet]);

  useEffect(() => {
    void loadSets();
  }, [loadSets]);

  const handleSelect = useCallback(
    async (setId: string) => {
      if (disabled || loading) return;
      const current = sets.find((s) => s.id === setId);
      if (current?.isActive) return;
      setLoading(true);
      try {
        const activated = await api.activateKeywordSet(setId);
        setSets((prev) =>
          prev.map((s) => ({ ...s, isActive: s.id === activated.id })),
        );
        notifyActiveSet(activated);
      } catch {
        toast.error("Failed to switch keyword set");
      } finally {
        setLoading(false);
      }
    },
    [disabled, loading, notifyActiveSet, sets],
  );

  const handleCreate = useCallback(async () => {
    const name = newSetName.trim();
    if (!name) {
      toast.error("Enter a name for the keyword set");
      return;
    }
    setCreating(true);
    try {
      const created = await api.createKeywordSet({ name, terms: [] });
      const activated = await api.activateKeywordSet(created.id);
      setSets((prev) => [
        ...prev.map((s) => ({ ...s, isActive: false })),
        { ...activated, isActive: true },
      ]);
      notifyActiveSet(activated);
      setNewSetName("");
      setShowCreate(false);
      toast.success(`Keyword set "${activated.name}" created`);
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "Failed to create keyword set";
      toast.error(message);
    } finally {
      setCreating(false);
    }
  }, [newSetName, notifyActiveSet]);

  const handleDelete = useCallback(
    async (setId: string) => {
      if (disabled || loading) return;
      setLoading(true);
      try {
        await api.deleteKeywordSet(setId);
        lastNotifiedIdRef.current = null;
        const list = await api.listKeywordSets();
        setSets(list);
        const active = list.find((s) => s.isActive) ?? list[0];
        if (active) notifyActiveSet(active);
        toast.success("Keyword set deleted");
      } catch (error) {
        const message =
          error instanceof Error
            ? error.message
            : "Failed to delete keyword set";
        toast.error(message);
      } finally {
        setLoading(false);
      }
    },
    [disabled, loading, notifyActiveSet],
  );

  const activeSet = sets.find((s) => s.isActive) ?? sets[0];
  return (
    <div className="space-y-3">
      <div className="flex flex-wrap items-center gap-2">
        <span className="text-sm font-medium shrink-0">Active set</span>
        {activeSet ? (
          <Select
            value={activeSet.id}
            onValueChange={handleSelect}
            disabled={disabled || loading}
          >
            <SelectTrigger
              className="w-[min(100%,240px)]"
              aria-label="Keyword set"
            >
              <SelectValue placeholder="Keyword set" />
            </SelectTrigger>
            <SelectContent>
              {sets.map((set) => (
                <SelectItem key={set.id} value={set.id}>
                  {set.name}
                  {set.isActive ? " (active)" : ""}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        ) : (
          <span className="text-sm text-muted-foreground">
            {loading ? "Loading sets…" : "No keyword sets"}
          </span>
        )}
        {loading ? (
          <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
        ) : null}
        <Button
          type="button"
          variant="outline"
          size="sm"
          disabled={disabled || creating}
          onClick={() => setShowCreate((v) => !v)}
        >
          <Plus className="h-4 w-4 mr-1" />
          New set
        </Button>
        {activeSet && sets.length > 1 ? (
          <Button
            type="button"
            variant="ghost"
            size="sm"
            disabled={disabled || loading}
            onClick={() => void handleDelete(activeSet.id)}
            title={`Delete "${activeSet.name}"`}
          >
            <Trash2 className="h-4 w-4" />
          </Button>
        ) : null}
      </div>
      {showCreate ? (
        <div className="flex flex-wrap items-center gap-2">
          <Input
            value={newSetName}
            onChange={(e) => setNewSetName(e.target.value)}
            placeholder="e.g. SDET, Caseware, Lead"
            className="max-w-xs"
            disabled={disabled || creating}
            onKeyDown={(e) => {
              if (e.key === "Enter") {
                e.preventDefault();
                void handleCreate();
              }
            }}
          />
          <Button
            type="button"
            size="sm"
            disabled={disabled || creating}
            onClick={() => void handleCreate()}
          >
            {creating ? <Loader2 className="h-4 w-4 animate-spin" /> : "Create"}
          </Button>
        </div>
      ) : null}
      {sets.length > 0 ? (
        <div className="flex flex-wrap gap-1.5 pt-1">
          {sets.map((set) => {
            const isActive = set.id === activeSet?.id;
            return (
              <button
                key={set.id}
                type="button"
                disabled={disabled || loading || isActive}
                onClick={() => void handleSelect(set.id)}
                className={cn(
                  "rounded-md border px-2.5 py-1 text-xs font-medium transition-colors",
                  isActive
                    ? "border-primary bg-primary/10 text-foreground"
                    : "border-border bg-muted/40 text-muted-foreground hover:bg-muted",
                )}
              >
                {set.name}
                <span className="ml-1 text-muted-foreground">
                  ({set.terms.length})
                </span>
              </button>
            );
          })}
        </div>
      ) : !loading ? (
        <p className="text-xs text-amber-600 dark:text-amber-400">
          No keyword sets loaded. Use &quot;New set&quot; or check that the API
          is running.
        </p>
      ) : null}
      <p className="text-xs text-muted-foreground">
        Switch between named lists for different searches. Terms below belong to
        the active set.
      </p>
    </div>
  );
};
