"use client";

import { useEffect, useRef, useState } from "react";
import { Check, ListFilter, Search, Tag, X } from "lucide-react";
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { cn } from "@/lib/utils";

/** A search affordance that expands from an icon into a text input. */
export function ExpandableSearch({
  value,
  onChange,
  placeholder,
  label = "Search",
}: {
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  label?: string;
}) {
  const [open, setOpen] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);
  const active = value.trim().length > 0;
  const expanded = open || active;

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

  if (!expanded) {
    return (
      <button
        type="button"
        onClick={() => setOpen(true)}
        aria-label={label}
        className="inline-flex size-7 items-center justify-center rounded-md border text-muted-foreground transition-colors hover:bg-accent"
      >
        <Search className="size-3.5" />
      </button>
    );
  }

  return (
    <div className="relative flex items-center">
      <Search className="pointer-events-none absolute left-2 size-3.5 text-muted-foreground" />
      <input
        ref={inputRef}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onBlur={() => {
          if (!active) setOpen(false);
        }}
        placeholder={placeholder}
        className="h-7 w-44 rounded-md border bg-background pl-7 pr-6 text-xs font-normal focus:outline-none focus-visible:ring-2 focus-visible:ring-ring"
      />
      {active && (
        <button
          type="button"
          onClick={() => {
            onChange("");
            setOpen(false);
          }}
          aria-label="Clear search"
          className="absolute right-1.5 text-muted-foreground hover:text-foreground"
        >
          <X className="size-3.5" />
        </button>
      )}
    </div>
  );
}

/** Multi-select filter over the tags currently in use. Matches pages that have
 * ANY of the selected tags. */
export function TagFilter({
  allTags,
  selected,
  onToggle,
  onClear,
}: {
  allTags: string[];
  selected: Set<string>;
  onToggle: (tag: string) => void;
  onClear: () => void;
}) {
  const active = selected.size > 0;

  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        render={
          <button
            type="button"
            aria-label="Filter by tags"
            className={cn(
              "inline-flex h-7 items-center gap-1 rounded-md border px-2 text-xs font-normal transition-colors hover:bg-accent",
              active
                ? "border-foreground/30 bg-accent font-medium"
                : "text-muted-foreground",
            )}
          >
            <Tag className="size-3.5 shrink-0" />
            <span className="truncate">
              {active
                ? `${selected.size} tag${selected.size > 1 ? "s" : ""}`
                : "Tags"}
            </span>
          </button>
        }
      />
      <DropdownMenuContent align="start" className="min-w-44">
        {allTags.length === 0 ? (
          <div className="px-2 py-1.5 text-xs text-muted-foreground">
            No tags yet
          </div>
        ) : (
          <>
            {allTags.map((tag) => (
              <DropdownMenuCheckboxItem
                key={tag}
                checked={selected.has(tag)}
                onCheckedChange={() => onToggle(tag)}
              >
                {tag}
              </DropdownMenuCheckboxItem>
            ))}
            {active && (
              <>
                <DropdownMenuSeparator />
                <DropdownMenuItem
                  onClick={onClear}
                  className="text-xs text-muted-foreground"
                >
                  Clear tags
                </DropdownMenuItem>
              </>
            )}
          </>
        )}
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

export const ALL = "all" as const;

export interface ExtraOption {
  value: string;
  label: string;
}

/**
 * A dropdown filter over a fixed set of options, plus an "All" reset and any
 * synthetic "group" options (e.g. status "Incomplete") rendered after All.
 */
export function EnumFilter({
  value,
  options,
  onChange,
  dotClass,
  allLabel = "All",
  ariaLabel,
  extraOptions,
}: {
  value: string;
  options: readonly string[];
  onChange: (value: string) => void;
  dotClass?: Record<string, string>;
  allLabel?: string;
  ariaLabel?: string;
  extraOptions?: ExtraOption[];
}) {
  const active = value !== ALL;
  const extra = extraOptions?.find((o) => o.value === value);
  const triggerLabel = value === ALL ? allLabel : extra ? extra.label : value;

  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        render={
          <button
            type="button"
            aria-label={ariaLabel}
            className={cn(
              "inline-flex h-7 max-w-full items-center gap-1 rounded-md border px-2 text-xs font-normal transition-colors hover:bg-accent",
              active
                ? "border-foreground/30 bg-accent font-medium"
                : "text-muted-foreground",
            )}
          >
            <ListFilter className="size-3.5 shrink-0" />
            <span className="truncate capitalize">{triggerLabel}</span>
          </button>
        }
      />
      <DropdownMenuContent align="start" className="min-w-44">
        <DropdownMenuItem onClick={() => onChange(ALL)} className="gap-2">
          <span className="flex-1">{allLabel}</span>
          {value === ALL && <Check className="size-3.5 opacity-70" />}
        </DropdownMenuItem>
        {extraOptions?.map((option) => (
          <DropdownMenuItem
            key={option.value}
            onClick={() => onChange(option.value)}
            className="gap-2"
          >
            <span className="flex-1">{option.label}</span>
            {value === option.value && (
              <Check className="size-3.5 opacity-70" />
            )}
          </DropdownMenuItem>
        ))}
        {options.map((option) => (
          <DropdownMenuItem
            key={option}
            onClick={() => onChange(option)}
            className="gap-2 capitalize"
          >
            {dotClass && (
              <span className={cn("size-2 rounded-full", dotClass[option])} />
            )}
            <span className="flex-1">{option}</span>
            {value === option && <Check className="size-3.5 opacity-70" />}
          </DropdownMenuItem>
        ))}
      </DropdownMenuContent>
    </DropdownMenu>
  );
}
