import * as React from "react";
import { cn } from "@/lib/utils";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";

/**
 * ColorPicker — WealthX Design System
 *
 * Popover-based color picker with preset swatches and a hex input field.
 * Designed for tenant white-label brand color configuration.
 *
 * Figma: https://www.figma.com/design/9V9F0NGVsif8LGmEhVjOcT/Design-System---shadcn
 */

// ---------------------------------------------------------------------------
// Preset palettes
// ---------------------------------------------------------------------------

export const COLOR_PICKER_PRESETS = [
  // Blues
  "#1E40AF",
  "#2563EB",
  "#3B82F6",
  "#60A5FA",
  // Purples
  "#7C3AED",
  "#8B5CF6",
  "#A78BFA",
  "#C4B5FD",
  // Greens
  "#15803D",
  "#16A34A",
  "#22C55E",
  "#4ADE80",
  // Reds
  "#B91C1C",
  "#DC2626",
  "#EF4444",
  "#F87171",
  // Oranges
  "#C2410C",
  "#EA580C",
  "#F97316",
  "#FB923C",
  // Teals
  "#0F766E",
  "#0D9488",
  "#14B8A6",
  "#2DD4BF",
  // Neutrals
  "#111827",
  "#374151",
  "#6B7280",
  "#D1D5DB",
];

// ---------------------------------------------------------------------------
// Utility
// ---------------------------------------------------------------------------

/** Returns true if the string is a valid 6-digit or 3-digit hex color. */
function isValidHex(value: string): boolean {
  return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(value);
}

/** Ensures value always has a leading `#`. */
function normalizeHex(value: string): string {
  const stripped = value.replace(/^#/, "");
  return `#${stripped}`;
}

// ---------------------------------------------------------------------------
// ColorSwatch
// ---------------------------------------------------------------------------

interface ColorSwatchProps {
  color: string;
  selected?: boolean;
  size?: "sm" | "md";
  onClick?: (color: string) => void;
  className?: string;
}

function ColorSwatch({
  color,
  selected,
  size = "md",
  onClick,
  className,
}: ColorSwatchProps) {
  return (
    <Button
      type="button"
      variant="ghost"
      title={color}
      aria-label={`Select color ${color}`}
      aria-pressed={selected}
      onClick={() => onClick?.(color)}
      className={cn(
        "relative shrink-0 p-0 transition-all outline-none shadow-[inset_0_0_0_1px_rgba(0,0,0,0.12)]",
        "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
        size === "md" ? "size-7" : "size-5",
        selected &&
          "ring-2 ring-foreground ring-offset-1 ring-offset-background",
        className
      )}
      style={{ backgroundColor: color }}
    />
  );
}

// ---------------------------------------------------------------------------
// ColorPickerContent (inner panel shown in popover)
// ---------------------------------------------------------------------------

interface ColorPickerContentProps {
  value: string;
  onChange: (color: string) => void;
  presets?: string[];
}

function ColorPickerContent({
  value,
  onChange,
  presets = COLOR_PICKER_PRESETS,
}: ColorPickerContentProps) {
  const [hexInput, setHexInput] = React.useState(value);
  const hexInputRef = React.useRef(hexInput);
  hexInputRef.current = hexInput;

  React.useEffect(() => {
    // Only sync from external value (e.g. swatch click) when the user's current
    // input doesn't already produce the same color — prevents cursor jump mid-type.
    if (value !== hexInputRef.current) {
      setHexInput(value);
    }
  }, [value]);

  function handleHexInputChange(e: React.ChangeEvent<HTMLInputElement>) {
    const raw = e.target.value;
    setHexInput(raw);
    const normalized = normalizeHex(raw);
    // Only commit on a complete 6-digit hex so intermediate 3-digit matches
    // (#abc shorthand) don't fire onChange mid-type and shift the cursor.
    if (/^#[0-9A-Fa-f]{6}$/.test(normalized)) {
      onChange(normalized);
    }
  }

  function handleHexBlur() {
    const normalized = normalizeHex(hexInput);
    if (isValidHex(normalized)) {
      setHexInput(normalized);
      if (normalized !== value) onChange(normalized);
    } else {
      setHexInput(value);
    }
  }

  const normalizedInput = normalizeHex(hexInput);
  const isValid = isValidHex(normalizedInput);

  return (
    <div data-slot="color-picker-content" className="flex flex-col gap-4">
      <div>
        <p className="mb-2 text-xs font-medium text-muted-foreground">
          Presets
        </p>
        <div className="grid grid-cols-7 gap-1.5">
          {presets.map((color) => (
            <ColorSwatch
              key={color}
              color={color}
              selected={value.toLowerCase() === color.toLowerCase()}
              onClick={onChange}
            />
          ))}
        </div>
      </div>

      <div>
        <p className="mb-2 text-xs font-medium text-muted-foreground">
          Custom hex
        </p>
        <div className="flex items-center gap-2">
          <label
            className="relative size-9 shrink-0 cursor-pointer border border-border"
            title="Open color picker"
            style={{
              backgroundColor: isValid ? normalizedInput : value,
            }}
          >
            <input
              type="color"
              aria-label="Native color picker"
              value={isValid ? normalizedInput : value}
              onChange={(e) => {
                setHexInput(e.target.value);
                onChange(e.target.value);
              }}
              className="absolute inset-0 h-full w-full cursor-pointer opacity-0"
            />
          </label>
          <Input
            aria-label="Hex color value"
            placeholder="#000000"
            value={hexInput}
            onChange={handleHexInputChange}
            onBlur={handleHexBlur}
            maxLength={7}
            className="h-9 flex-1 font-mono text-sm uppercase"
          />
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// ColorPicker (popover trigger + content)
// ---------------------------------------------------------------------------

interface ColorPickerProps {
  /** The current color value (hex string, e.g. `"#3B82F6"`). */
  value?: string;
  /** Default value when uncontrolled. */
  defaultValue?: string;
  /** Called whenever the selected color changes. */
  onChange?: (color: string) => void;
  /** Preset colors shown in the swatch grid. Defaults to `COLOR_PICKER_PRESETS`. */
  presets?: string[];
  /** Disable the picker. */
  disabled?: boolean;
  /** Optional label shown above the trigger. */
  label?: string;
  className?: string;
}

function ColorPicker({
  value: controlledValue,
  defaultValue = "#3B82F6",
  onChange,
  presets,
  disabled,
  label,
  className,
}: ColorPickerProps) {
  const isControlled = controlledValue !== undefined;
  const [internalValue, setInternalValue] = React.useState(defaultValue);
  const color = isControlled ? controlledValue : internalValue;
  const [open, setOpen] = React.useState(false);

  React.useEffect(() => {
    if (disabled) setOpen(false);
  }, [disabled]);

  function handleChange(newColor: string) {
    if (!isControlled) setInternalValue(newColor);
    onChange?.(newColor);
  }

  return (
    <div
      data-slot="color-picker"
      className={cn("inline-flex flex-col gap-1.5 font-sans", className)}
    >
      {label && (
        <span className="text-sm font-medium text-foreground">{label}</span>
      )}
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverTrigger
          disabled={disabled}
          className={cn(
            "flex h-9 min-w-[140px] cursor-pointer items-center gap-2.5 border border-input bg-background px-3 text-sm outline-none transition-colors",
            "hover:border-ring",
            "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
            "disabled:cursor-not-allowed disabled:opacity-50"
          )}
        >
          <span
            aria-hidden
            className="size-5 shrink-0 border border-border/50"
            style={{ backgroundColor: color }}
          />
          <span className="font-mono text-xs uppercase tracking-wide">
            {color}
          </span>
        </PopoverTrigger>
        <PopoverContent
          className="w-[220px] p-4"
          align="start"
          data-shadcn-scope
        >
          <ColorPickerContent
            value={color}
            onChange={handleChange}
            presets={presets}
          />
        </PopoverContent>
      </Popover>
    </div>
  );
}

export {
  ColorPicker,
  ColorPickerContent,
  ColorSwatch,
  isValidHex,
  normalizeHex,
};
export type { ColorPickerProps, ColorPickerContentProps, ColorSwatchProps };
