/**
 * Icon Picker
 *
 * Allows users to pick an icon + color from @untitledui/icons, upload an image,
 * or remove the current icon. Stores the selection as an icon:// URL string.
 */

import { Button } from "@decocms/ui/components/button.tsx";
import { Input } from "@decocms/ui/components/input.tsx";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@decocms/ui/components/popover.tsx";
import { ScrollArea } from "@decocms/ui/components/scroll-area.tsx";
import { cn } from "@decocms/ui/lib/utils.ts";
import { Edit05, SearchMd, Shuffle01, Upload01 } from "@untitledui/icons";
import { useRef, useState } from "react";
import { toast } from "sonner";
import { useT } from "@/i18n/use-t.ts";
import {
  AGENT_ICON_COLORS,
  AgentAvatar,
  buildIconString,
  buildImageIconString,
  filterIconNames,
  getIconColor,
  getIconComponent,
  getIconNames,
  getSizeRadius,
  humanizeIconName,
  parseIconString,
  type AgentAvatarSize,
} from "./agent-icon";

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

interface IconPickerProps {
  value: string | null | undefined;
  onChange: (icon: string | null) => void;
  onColorChange?: (color: string) => void;
  name: string;
  size?: AgentAvatarSize;
  className?: string;
  avatarClassName?: string;
  showHoverOverlay?: boolean;
  disabled?: boolean;
}

// ---------------------------------------------------------------------------
// Tabs
// ---------------------------------------------------------------------------

type PickerTab = "icons" | "upload";

// ---------------------------------------------------------------------------
// IconPicker
// ---------------------------------------------------------------------------

export function IconPicker({
  value,
  onChange,
  onColorChange: onColorChangeProp,
  name,
  size = "lg",
  className,
  avatarClassName,
  showHoverOverlay = true,
  disabled = false,
}: IconPickerProps) {
  const t = useT();
  const [open, setOpen] = useState(false);
  const [tab, setTab] = useState<PickerTab>("icons");
  const [search, setSearch] = useState("");
  // Local fallback color used only when `value` does not encode a color
  // (i.e. fallback type). When `value` carries a color it wins, so prop
  // updates stay in sync with the picker UI.
  const [fallbackColor, setFallbackColor] = useState("blue");
  const parsedValue = parseIconString(value);
  const selectedColor =
    parsedValue.type === "icon"
      ? parsedValue.color
      : parsedValue.type === "url" && parsedValue.color
        ? parsedValue.color
        : fallbackColor;

  const handleSelectIcon = (iconName: string) => {
    onChange(buildIconString(iconName, selectedColor));
  };

  const handleColorChange = (color: string) => {
    setFallbackColor(color);
    onColorChangeProp?.(color);
    if (parsedValue.type === "icon") {
      onChange(buildIconString(parsedValue.name, color));
    } else if (parsedValue.type === "url") {
      // Persist color with image URL
      onChange(buildImageIconString(parsedValue.url, color));
    }
  };

  const handleUpload = (dataUrl: string) => {
    // Encode the current selected color into the image URL
    onChange(buildImageIconString(dataUrl, selectedColor));
    setOpen(false);
  };

  const handleRandomIcon = () => {
    const names = getIconNames();
    const randomName = names[Math.floor(Math.random() * names.length)]!;
    onChange(buildIconString(randomName, selectedColor));
  };

  return (
    <Popover open={disabled ? false : open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <button
          type="button"
          data-testid="icon-picker-trigger"
          aria-label="Change icon"
          disabled={disabled}
          className={cn(
            "relative group overflow-hidden",
            disabled ? "cursor-default opacity-50" : "cursor-pointer",
            getSizeRadius(size),
            className,
          )}
        >
          <AgentAvatar
            icon={value}
            name={name}
            size={size}
            className={avatarClassName}
          />
          {showHoverOverlay && !disabled && (
            <div className="absolute inset-0 flex items-center justify-center bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity">
              <Edit05 size={16} className="text-white" />
            </div>
          )}
        </button>
      </PopoverTrigger>
      <PopoverContent
        align="start"
        className="w-80 p-0"
        onOpenAutoFocus={(e) => e.preventDefault()}
      >
        <div className="flex flex-col">
          {/* Preview */}
          <div className="flex items-center justify-center py-4">
            <AgentAvatar icon={value} name={name} size="xl" />
          </div>

          {/* Tab bar */}
          <div
            role="tablist"
            aria-label="Icon source"
            className="flex items-center border-b border-border px-3"
            onKeyDown={(e) => {
              if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
              e.preventDefault();
              const nextTab = tab === "icons" ? "upload" : "icons";
              setTab(nextTab);
              document.getElementById(`icon-picker-tab-${nextTab}`)?.focus();
            }}
          >
            <button
              id="icon-picker-tab-icons"
              type="button"
              role="tab"
              aria-selected={tab === "icons"}
              aria-controls="icon-picker-panel-icons"
              tabIndex={tab === "icons" ? 0 : -1}
              onClick={() => setTab("icons")}
              className={cn(
                "px-3 py-2 text-sm font-medium border-b-2 -mb-px transition-colors",
                tab === "icons"
                  ? "border-foreground text-foreground"
                  : "border-transparent text-muted-foreground hover:text-foreground",
              )}
            >
              {t("common.iconPicker.iconsTab")}
            </button>
            <button
              id="icon-picker-tab-upload"
              type="button"
              role="tab"
              aria-selected={tab === "upload"}
              aria-controls="icon-picker-panel-upload"
              tabIndex={tab === "upload" ? 0 : -1}
              onClick={() => setTab("upload")}
              className={cn(
                "px-3 py-2 text-sm font-medium border-b-2 -mb-px transition-colors",
                tab === "upload"
                  ? "border-foreground text-foreground"
                  : "border-transparent text-muted-foreground hover:text-foreground",
              )}
            >
              {t("common.iconPicker.uploadTab")}
            </button>
            <div className="flex-1" />
          </div>

          {/* Tab content */}
          {tab === "icons" ? (
            <div
              id="icon-picker-panel-icons"
              role="tabpanel"
              aria-labelledby="icon-picker-tab-icons"
            >
              <IconsTab
                search={search}
                onSearchChange={setSearch}
                selectedColor={selectedColor}
                onColorChange={handleColorChange}
                onSelectIcon={handleSelectIcon}
                onRandom={handleRandomIcon}
                currentIconName={
                  parsedValue.type === "icon" ? parsedValue.name : null
                }
              />
            </div>
          ) : (
            <div
              id="icon-picker-panel-upload"
              role="tabpanel"
              aria-labelledby="icon-picker-tab-upload"
            >
              <UploadTab onUpload={handleUpload} />
            </div>
          )}
        </div>
      </PopoverContent>
    </Popover>
  );
}

// ---------------------------------------------------------------------------
// Icons Tab
// ---------------------------------------------------------------------------

function ColorPickerDropdown({
  selectedColor,
  onColorChange,
}: {
  selectedColor: string;
  onColorChange: (color: string) => void;
}) {
  const t = useT();
  const [open, setOpen] = useState(false);
  const color = getIconColor(selectedColor);

  return (
    <Popover open={open} onOpenChange={setOpen}>
      <PopoverTrigger asChild>
        <button
          type="button"
          className={cn(
            "h-6 w-6 rounded-full shrink-0 ring-2 ring-offset-2 ring-offset-background transition-all cursor-pointer hover:scale-110",
            color.dot,
            "ring-foreground/20",
          )}
          title={t("common.iconPicker.changeColor")}
          aria-label={t("common.iconPicker.changeColor")}
        />
      </PopoverTrigger>
      <PopoverContent
        align="start"
        side="right"
        sideOffset={8}
        className="w-auto p-2"
        onOpenAutoFocus={(e) => e.preventDefault()}
      >
        <div className="grid grid-cols-4 gap-1">
          {AGENT_ICON_COLORS.map((c) => (
            <button
              key={c.name}
              type="button"
              onClick={() => {
                onColorChange(c.name);
                setOpen(false);
              }}
              className={cn(
                "h-5 w-5 rounded-full transition-all shrink-0 cursor-pointer",
                c.dot,
                selectedColor === c.name
                  ? "ring-2 ring-offset-1 ring-offset-background ring-foreground/30 scale-110"
                  : "hover:scale-110",
              )}
              title={c.name}
              aria-label={c.name}
            />
          ))}
        </div>
      </PopoverContent>
    </Popover>
  );
}

function IconsTab({
  search,
  onSearchChange,
  selectedColor,
  onColorChange,
  onSelectIcon,
  onRandom,
  currentIconName,
}: {
  search: string;
  onSearchChange: (s: string) => void;
  selectedColor: string;
  onColorChange: (color: string) => void;
  onSelectIcon: (name: string) => void;
  onRandom: () => void;
  currentIconName: string | null;
}) {
  const t = useT();
  const allNames = getIconNames();
  const color = getIconColor(selectedColor);
  const filteredNames = filterIconNames(allNames, search);

  return (
    <div className="flex flex-col">
      {/* Search + controls */}
      <div className="flex items-center gap-2 px-3 py-2">
        <div className="relative flex-1">
          <SearchMd
            size={14}
            className="absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground pointer-events-none"
          />
          <Input
            value={search}
            onChange={(e) => onSearchChange(e.target.value)}
            placeholder={t("common.iconPicker.filterPlaceholder")}
            className="h-8 text-xs pl-7"
          />
        </div>
        <button
          type="button"
          onClick={onRandom}
          className="h-8 w-8 flex items-center justify-center rounded-md border border-border hover:bg-accent transition-colors shrink-0"
          title={t("common.iconPicker.randomIcon")}
          aria-label={t("common.iconPicker.randomIcon")}
        >
          <Shuffle01 size={14} className="text-muted-foreground" />
        </button>
        <ColorPickerDropdown
          selectedColor={selectedColor}
          onColorChange={onColorChange}
        />
      </div>

      {/* Icon grid */}
      <ScrollArea className="h-56">
        <div className="grid grid-cols-9 gap-0.5 px-2 pb-2">
          {filteredNames.map((iconName) => {
            const IconComp = getIconComponent(iconName);
            if (!IconComp) return null;

            return (
              <button
                key={iconName}
                type="button"
                onClick={() => onSelectIcon(iconName)}
                className={cn(
                  "h-8 w-8 flex items-center justify-center rounded-md transition-colors cursor-pointer",
                  currentIconName === iconName
                    ? cn(color.bg, color.text)
                    : cn(color.text, "hover:bg-accent"),
                )}
                title={iconName}
                aria-label={humanizeIconName(iconName)}
              >
                <IconComp size={18} />
              </button>
            );
          })}
        </div>
        {filteredNames.length === 0 && (
          <div className="flex items-center justify-center py-8 text-sm text-muted-foreground">
            {t("common.iconPicker.noIconsFound")}
          </div>
        )}
      </ScrollArea>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Upload Tab
// ---------------------------------------------------------------------------

function UploadTab({ onUpload }: { onUpload: (dataUrl: string) => void }) {
  const t = useT();
  const fileInputRef = useRef<HTMLInputElement>(null);

  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;

    if (file.size > 2 * 1024 * 1024) {
      toast.error(t("common.iconPicker.imageTooLarge"));
      event.target.value = "";
      return;
    }

    const reader = new FileReader();
    reader.onerror = () => {
      toast.error(t("common.iconPicker.failedToReadImage"));
      if (fileInputRef.current) fileInputRef.current.value = "";
    };
    reader.onloadend = () => {
      if (reader.readyState === FileReader.DONE && reader.result) {
        onUpload(reader.result as string);
      }
      if (fileInputRef.current) fileInputRef.current.value = "";
    };
    reader.readAsDataURL(file);
  };

  const [pasteUrl, setPasteUrl] = useState("");

  const handleApplyUrl = () => {
    const trimmed = pasteUrl.trim();
    if (trimmed) {
      onUpload(trimmed);
      setPasteUrl("");
    }
  };

  return (
    <div className="flex flex-col gap-3 p-4">
      <input
        type="file"
        ref={fileInputRef}
        className="hidden"
        accept="image/*"
        onChange={handleFileChange}
      />

      <button
        type="button"
        onClick={() => fileInputRef.current?.click()}
        className="h-24 rounded-lg border-2 border-dashed border-border hover:border-foreground/50 hover:bg-accent/50 transition-colors flex flex-col items-center justify-center gap-2 text-muted-foreground hover:text-foreground"
      >
        <Upload01 size={20} />
        <span className="text-xs">{t("common.iconPicker.uploadHint")}</span>
      </button>

      <div className="flex items-center gap-2">
        <span className="text-xs text-muted-foreground">
          {t("common.iconPicker.or")}
        </span>
        <div className="flex-1 h-px bg-border" />
      </div>

      <div className="flex items-center gap-1.5">
        <Input
          value={pasteUrl}
          onChange={(e) => setPasteUrl(e.target.value)}
          placeholder={t("common.iconPicker.pasteUrlPlaceholder")}
          className="h-8 text-xs flex-1"
          onKeyDown={(e) => {
            if (e.key === "Enter") {
              e.preventDefault();
              handleApplyUrl();
            }
          }}
        />
        <Button
          variant="outline"
          size="sm"
          className="h-8 px-3 text-xs shrink-0"
          onClick={handleApplyUrl}
          disabled={!pasteUrl.trim()}
        >
          {t("common.iconPicker.apply")}
        </Button>
      </div>
    </div>
  );
}
