import React from "react";
import { RangeSlider } from "./RangeSlider";

export interface ColorPickerProps {
  /** The current color value (hex) */
  value: string;
  /** Callback when the color changes */
  onChange: (value: string) => void;
  /** Label for the color picker */
  label: string;
  /** Optional description displayed below the label */
  description?: string;
  /** Optional additional class name for the container */
  className?: string;
  /** Optional placeholder for the text input */
  placeholder?: string;
  /** Optional action button (e.g., "Reset to Auto") */
  actionButton?: React.ReactNode;
  /** Enable an opacity slider for rgba-style colors */
  allowAlpha?: boolean;
}

export interface ColorPickerActionButtonProps {
  label: string;
  onClick: () => void;
  disabled?: boolean;
}

export function ColorPickerActionButton({
  label,
  onClick,
  disabled = false,
}: ColorPickerActionButtonProps): React.ReactElement {
  return (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      className="b3-wvs-shell-btn is-secondary b3-wvs-h-10 b3-wvs-whitespace-nowrap b3-wvs-px-4"
    >
      {label}
    </button>
  );
}

/**
 * A reusable color picker component with color input and text input.
 */
export function ColorPicker({
  value,
  onChange,
  label,
  description,
  className = "",
  placeholder,
  actionButton,
  allowAlpha = false,
}: ColorPickerProps): React.ReactElement {
  const clamp = (rawValue: number, min: number, max: number): number =>
    Math.min(max, Math.max(min, rawValue));

  const expandHex = (hex: string): string => {
    const raw = hex.replace("#", "").trim();
    if (raw.length === 3 || raw.length === 4) {
      return raw
        .slice(0, raw.length === 4 ? 4 : 3)
        .split("")
        .map((char) => char + char)
        .join("")
        .slice(0, 6);
    }
    return raw.slice(0, 6);
  };

  const rgbToHex = (r: number, g: number, b: number): string =>
    `#${[r, g, b]
      .map((channel) =>
        clamp(Math.round(channel), 0, 255).toString(16).padStart(2, "0"),
      )
      .join("")}`;

  const parseColorValue = (
    rawValue: string,
  ): { hex: string; alpha: number } => {
    const trimmed = (rawValue || "").trim();

    if (!trimmed || trimmed.toLowerCase() === "transparent") {
      return { hex: "#000000", alpha: 0 };
    }

    const hexMatch = trimmed.match(/^#([0-9a-f]{3,8})$/i);
    if (hexMatch) {
      const normalized = expandHex(trimmed);
      const rawHex = hexMatch[1];
      const alphaHex =
        rawHex.length === 4
          ? `${rawHex[3]}${rawHex[3]}`
          : rawHex.length === 8
            ? rawHex.slice(6, 8)
            : "";

      return {
        hex: `#${normalized}`.toLowerCase(),
        alpha: alphaHex ? clamp(parseInt(alphaHex, 16) / 255, 0, 1) : 1,
      };
    }

    const rgbaMatch = trimmed.match(/^rgba?\((.+)\)$/i);
    if (rgbaMatch) {
      const parts = rgbaMatch[1].split(",").map((part) => part.trim());
      if (parts.length >= 3) {
        const red = Number(parts[0]);
        const green = Number(parts[1]);
        const blue = Number(parts[2]);
        const alpha = parts.length >= 4 ? Number(parts[3]) : 1;

        if (
          [red, green, blue].every(Number.isFinite) &&
          Number.isFinite(alpha)
        ) {
          return {
            hex: rgbToHex(red, green, blue).toLowerCase(),
            alpha: clamp(alpha, 0, 1),
          };
        }
      }
    }

    return { hex: "#000000", alpha: 1 };
  };

  const formatAlpha = (alpha: number): string => {
    const rounded = Math.round(clamp(alpha, 0, 1) * 100) / 100;
    return rounded.toFixed(2).replace(/0+$/, "").replace(/\.$/, "");
  };

  const toColorString = (hex: string, alpha: number): string => {
    const normalizedHex = expandHex(hex);
    const red = parseInt(normalizedHex.slice(0, 2), 16);
    const green = parseInt(normalizedHex.slice(2, 4), 16);
    const blue = parseInt(normalizedHex.slice(4, 6), 16);
    const safeAlpha = clamp(alpha, 0, 1);

    if (safeAlpha <= 0) {
      return `rgba(${red}, ${green}, ${blue}, 0)`;
    }

    if (safeAlpha >= 1) {
      return `#${normalizedHex}`.toLowerCase();
    }

    return `rgba(${red}, ${green}, ${blue}, ${formatAlpha(safeAlpha)})`;
  };

  const parsedColor = parseColorValue(value);

  return (
    <div className={className}>
      <label className="b3-wvs-block b3-wvs-text-sm b3-wvs-font-medium b3-wvs-text-gray-700">
        {label}
      </label>
      {description && (
        <p className="b3-wvs-mt-1 b3-wvs-text-xs b3-wvs-text-gray-500 b3-wvs-mb-2">
          {description}
        </p>
      )}
      <div
        className={`${description ? "" : "b3-wvs-mt-1 "}b3-wvs-flex b3-wvs-items-center b3-wvs-gap-3 b3-wvs-min-w-0`}
      >
        <input
          type="color"
          value={parsedColor.hex}
          onChange={(e) =>
            onChange(
              allowAlpha
                ? toColorString(e.target.value, parsedColor.alpha)
                : e.target.value,
            )
          }
          className="b3-wvs-h-10 b3-wvs-w-14 b3-wvs-cursor-pointer b3-wvs-rounded-md b3-wvs-border b3-wvs-border-slate-300 b3-wvs-bg-white"
        />
        <input
          type="text"
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder={placeholder}
          className="b3-wvs-flex-1 b3-wvs-min-w-0 b3-wvs-rounded-md b3-wvs-border b3-wvs-border-slate-300 b3-wvs-bg-white b3-wvs-px-3 b3-wvs-py-2 b3-wvs-text-sm b3-wvs-font-mono b3-wvs-text-slate-700 focus:b3-wvs-border-admin focus:b3-wvs-outline-none focus:b3-wvs-ring-2 focus:b3-wvs-ring-admin"
        />
        {actionButton}
      </div>
      {allowAlpha && (
        <RangeSlider
          className="b3-wvs-mt-3"
          label="Transparency"
          description="Adjust the overlay opacity without editing the rgba value manually."
          value={Math.round((1 - parsedColor.alpha) * 100)}
          min={0}
          max={100}
          step={1}
          unit="%"
          onChange={(sliderValue) =>
            onChange(toColorString(parsedColor.hex, 1 - sliderValue / 100))
          }
        />
      )}
    </div>
  );
}
