import { useMemo, useState } from "react";
import { Check } from "lucide-react";
import { AVATAR_COLORS } from "~/lib/avatar-colors";
import { generateFlagConfig } from "~/lib/flag-generator";
import { FLAG_PATTERNS, type FlagConfig, type FlagPattern } from "~/lib/flag-types";
import { cn } from "~/lib/utils";
import { Input } from "~/components/ui/input";
import { Label } from "~/components/ui/label";
import { FlagSvg } from "~/components/ui/FlagSvg";

interface FlagBuilderProps {
  value?: FlagConfig | null;
  seed: string;
  onChange: (config: FlagConfig) => void;
}

const SWATCHES = [
  ...AVATAR_COLORS,
  "#22c55e",
  "#14b8a6",
  "#06b6d4",
  "#0ea5e9",
  "#6366f1",
  "#a855f7",
  "#d946ef",
  "#ec4899",
  "#f43f5e",
  "#dc2626",
  "#f97316",
  "#eab308",
  "#84cc16",
  "#ffffff",
  "#d1d5db",
  "#6b7280",
  "#111827",
  "#000000",
];
const COLOR_SLOT_KEYS = ["primary", "secondary", "accent"];
const FALLBACK_COLORS = ["#adf661", "#111827", "#ffffff"];
const HEX_COLOR_RE = /^#[0-9a-fA-F]{6}$/;

function normalizeColors(colors: string[]): string[] {
  return [
    colors[0] ?? FALLBACK_COLORS[0],
    colors[1] ?? FALLBACK_COLORS[1],
    colors[2] ?? FALLBACK_COLORS[2],
  ];
}

export function FlagBuilder({ value: configValue, seed, onChange }: FlagBuilderProps) {
  const initial = useMemo(() => configValue ?? generateFlagConfig(seed), [seed, configValue]);
  const [customInputs, setCustomInputs] = useState(() => normalizeColors(initial.colors));
  const [selectedColorIndex, setSelectedColorIndex] = useState(0);
  const colors = normalizeColors(initial.colors);
  const config = { ...initial, colors };
  const colorSlots = colors.map((color, index) => ({
    key: COLOR_SLOT_KEYS[index],
    label: `Color ${index + 1}`,
    color,
    index,
  }));
  const activeColorIndex = Math.min(selectedColorIndex, colors.length - 1);
  const activeColor = colors[activeColorIndex];
  const customColor = customInputs[activeColorIndex] ?? activeColor;
  const isValidCustomColor = HEX_COLOR_RE.test(customColor);

  function updatePattern(pattern: FlagPattern) {
    onChange({ ...config, pattern });
  }

  function updateColor(index: number, color: string) {
    const nextColors = [...colors];
    nextColors[index] = color;
    onChange({ ...config, colors: nextColors });
  }

  return (
    <div className="space-y-5">
      <div className="grid grid-cols-3 gap-2 sm:grid-cols-4">
        {FLAG_PATTERNS.map((pattern) => {
          const selected = config.pattern === pattern;
          return (
            <button
              key={pattern}
              type="button"
              title={pattern}
              aria-label={pattern}
              aria-pressed={selected}
              onClick={() => updatePattern(pattern)}
              className={cn(
                "relative flex aspect-square items-center justify-center rounded-md border bg-background p-1 transition-colors",
                selected ? "border-[#adf661] ring-2 ring-[#adf661]/30" : "border-border hover:border-muted-foreground"
              )}
            >
              <FlagSvg config={{ ...config, pattern }} size={60} className="h-full w-full" />
              {selected && (
                <span className="absolute right-1 top-1 rounded-full bg-[#adf661] p-0.5 text-black">
                  <Check className="h-3 w-3" />
                </span>
              )}
            </button>
          );
        })}
      </div>

      <div className="space-y-3">
        <div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
          {colorSlots.map((slot) => (
            <button
              key={slot.key}
              type="button"
              aria-pressed={activeColorIndex === slot.index}
              onClick={() => setSelectedColorIndex(slot.index)}
              className={cn(
                "flex h-10 items-center gap-2 rounded-md border px-2 text-sm font-medium transition-colors",
                activeColorIndex === slot.index
                  ? "border-[#adf661] bg-[#adf661]/10"
                  : "border-border hover:border-muted-foreground"
              )}
            >
              <span
                className="h-5 w-5 shrink-0 rounded-sm border border-border"
                style={{ backgroundColor: slot.color }}
              />
              {slot.label}
            </button>
          ))}
        </div>

        <div className="space-y-2">
          <Label>{colorSlots[activeColorIndex]?.label ?? "Color"}</Label>
          <div className="flex flex-wrap items-center gap-2">
            {SWATCHES.map((swatch) => (
              <button
                key={swatch}
                type="button"
                title={swatch}
                aria-label={`Use ${swatch}`}
                onClick={() => updateColor(activeColorIndex, swatch)}
                className={cn(
                  "h-8 w-8 rounded-md border transition-transform hover:scale-105",
                  activeColor.toLowerCase() === swatch.toLowerCase()
                    ? "border-[#adf661] ring-2 ring-[#adf661]/30"
                    : "border-border"
                )}
                style={{ backgroundColor: swatch }}
              />
            ))}
            <button
              type="button"
              title={isValidCustomColor ? customColor : "Custom color"}
              aria-label={isValidCustomColor ? `Use custom color ${customColor}` : "Custom color"}
              disabled={!isValidCustomColor}
              onClick={() => {
                if (isValidCustomColor) updateColor(activeColorIndex, customColor);
              }}
              className={cn(
                "h-8 w-8 rounded-md border transition-transform",
                isValidCustomColor ? "hover:scale-105" : "cursor-not-allowed opacity-40",
                isValidCustomColor && activeColor.toLowerCase() === customColor.toLowerCase()
                  ? "border-[#adf661] ring-2 ring-[#adf661]/30"
                  : "border-border"
              )}
              style={{ backgroundColor: isValidCustomColor ? customColor : "transparent" }}
            />
            <Input
              value={customInputs[activeColorIndex] ?? activeColor}
              onChange={(event) => {
                const inputValue = event.target.value;
                const next = [...customInputs];
                next[activeColorIndex] = inputValue;
                setCustomInputs(next);
                if (HEX_COLOR_RE.test(inputValue)) updateColor(activeColorIndex, inputValue);
              }}
              maxLength={7}
              className="h-8 w-28"
            />
          </div>
        </div>
      </div>
    </div>
  );
}
