import { type FC, type InputHTMLAttributes, useEffect, useRef, useState } from "react";
import { HexAlphaColorPicker, HexColorInput, HexColorPicker } from "react-colorful";
import { clx } from "../helpers/utils";
import Error from "./Error";

type Props = {
  label?: string;
  className?: string;
  error_text?: string;
  isNotRequired?: boolean;
  value?: string;
  onChange?: (value: string) => void;
  opacity?: number;
  onOpacityChange?: (value: number) => void;
  opacityLabel?: string;
} & Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "value">;

const ColorPicker: FC<Props> = (props: Props) => {
  const [color, setColor] = useState<string>(props.value || "#000000");
  const [opacityDisplay, setOpacityDisplay] = useState<string>(`${props.opacity ?? 100}`);
  const [isOpen, setIsOpen] = useState(false);
  const wrapperRef = useRef<HTMLDivElement>(null);
  const showOpacity = props.onOpacityChange !== undefined;

  const clampOpacity = (rawValue: number): number => Math.min(100, Math.max(0, rawValue));

  const normalizeHex = (value: string): string => {
    if (!value) return "#000000";
    const withHash = value.startsWith("#") ? value : `#${value}`;
    const shortMatch = /^#([0-9A-Fa-f]{3})$/.exec(withHash);
    if (shortMatch) {
      const [r, g, b] = shortMatch[1]!.split("");
      return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
    }
    const longMatch = /^#([0-9A-Fa-f]{6})$/.exec(withHash);
    if (longMatch) {
      return `#${longMatch[1]}`.toLowerCase();
    }
    return "#000000";
  };

  const toHexAlpha = (hex: string, opacity: number): string => {
    const normalizedHex = normalizeHex(hex);
    const alpha = Math.round((clampOpacity(opacity) / 100) * 255)
      .toString(16)
      .padStart(2, "0");
    return `${normalizedHex}${alpha}`;
  };

  const fromHexAlpha = (hexAlpha: string): { hex: string; opacity: number } => {
    const match = /^#([0-9A-Fa-f]{8})$/.exec(hexAlpha);
    if (!match) {
      return {
        hex: normalizeHex(hexAlpha),
        opacity: 100,
      };
    }
    const rgbaHex = match[1]!.toLowerCase();
    const rgb = `#${rgbaHex.slice(0, 6)}`;
    const alphaHex = rgbaHex.slice(6, 8);
    const opacity = Math.round((parseInt(alphaHex, 16) / 255) * 100);
    return { hex: rgb, opacity: clampOpacity(opacity) };
  };

  const inputClass = clx("w-full bg-white h-[34px] text-black block pl-10 pr-10 text-xs rounded-xl border border-border", props.readOnly && "bg-gray-100 border-0 text-description");

  const handleColorChange = (newColor: string) => {
    const normalized = normalizeHex(newColor);
    setColor(normalized);
    props.onChange?.(normalized);
  };

  const togglePicker = () => {
    if (props.readOnly) return;
    setIsOpen((prev) => !prev);
  };

  useEffect(() => {
    if (props.value !== undefined) {
      setColor(normalizeHex(props.value));
    }
  }, [props.value]);

  useEffect(() => {
    if (props.opacity !== undefined) {
      setOpacityDisplay(`${props.opacity}`);
    }
  }, [props.opacity]);

  useEffect(() => {
    if (!isOpen) return;

    const handlePointerDownOutside = (event: MouseEvent) => {
      if (!wrapperRef.current?.contains(event.target as Node)) {
        setIsOpen(false);
      }
    };

    window.addEventListener("mousedown", handlePointerDownOutside);
    return () => window.removeEventListener("mousedown", handlePointerDownOutside);
  }, [isOpen]);

  const handleOpacityChange = (rawValue: string) => {
    setOpacityDisplay(rawValue);
    const numValue = parseInt(rawValue, 10);
    if (!Number.isNaN(numValue)) {
      props.onOpacityChange?.(clampOpacity(numValue));
    }
  };

  const handleOpacityBlur = (rawValue: string) => {
    const numValue = parseInt(rawValue, 10) || 0;
    const clampedValue = clampOpacity(numValue);
    setOpacityDisplay(`${clampedValue}`);
    props.onOpacityChange?.(clampedValue);
  };

  const handleAlphaPickerChange = (hexAlpha: string) => {
    const { hex, opacity } = fromHexAlpha(hexAlpha);
    setColor(hex);
    setOpacityDisplay(`${opacity}`);
    props.onChange?.(hex);
    props.onOpacityChange?.(opacity);
  };

  const colorField = (
    <div className={clx("w-full", showOpacity && "flex-1")}>
      <label className="text-xs">{props.label}</label>

      <div className={clx("w-full relative mt-1 rounded-xl", !props.readOnly && "cursor-pointer")}>
        <input
          type="text"
          value={color}
          onChange={(event) => handleColorChange(event.target.value)}
          placeholder="#000000"
          readOnly={props.readOnly}
          title={!props.readOnly ? "کلیک برای باز کردن انتخابگر رنگ" : undefined}
          onClick={togglePicker}
          className={`${inputClass} ${props.readOnly ? "" : "cursor-pointer"}`}
        />

        <span
          aria-hidden
          className={clx("absolute top-0 bottom-0 my-auto left-1 flex items-center justify-center min-h-[34px] min-w-[34px] rounded-lg pointer-events-none", props.readOnly && "opacity-50")}
        >
          {/* <img
                        src={ColorfilterIcon}
                        alt=''
                        className='size-7 select-none'
                    /> */}
        </span>

        <span
          aria-hidden
          className={clx("absolute top-0 bottom-0 my-auto right-1 flex items-center justify-center min-h-[34px] min-w-[34px] rounded-lg pointer-events-none", props.readOnly && "opacity-50")}
        >
          <span className="block w-5 h-5 rounded-full border border-border shadow-sm" style={{ backgroundColor: color }} />
        </span>

        {isOpen && !props.readOnly && (
          <div className="absolute right-0 z-50 mt-2 w-full rounded-xl border border-border bg-white p-3 shadow-lg space-y-3">
            <div className="space-y-1">
              {showOpacity ? (
                <HexAlphaColorPicker color={toHexAlpha(color, Number(opacityDisplay) || 100)} onChange={handleAlphaPickerChange} />
              ) : (
                <HexColorPicker color={color} onChange={handleColorChange} />
              )}
            </div>
            <div className="flex items-center gap-2">
              <HexColorInput color={color} onChange={handleColorChange} prefixed className="h-9 max-w-[115px] flex-1 rounded-lg border border-border px-2 text-xs" />
              {showOpacity && (
                <div className="flex-1">
                  <input
                    type="number"
                    min={0}
                    max={100}
                    value={opacityDisplay}
                    onChange={(e) => handleOpacityChange(e.target.value)}
                    onBlur={(e) => handleOpacityBlur(e.target.value)}
                    className="h-9 w-full rounded-lg border border-border px-2 text-xs"
                    title={props.opacityLabel ?? "شفافیت"}
                  />
                </div>
              )}
            </div>
            {showOpacity && (
              <div className="text-xs text-gray-500">
                {props.opacityLabel ?? "شفافیت"}: {opacityDisplay}%
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );

  return (
    <div ref={wrapperRef} className={clx("w-full", props.className)}>
      {colorField}

      {props.error_text && <Error errorText={props.error_text} />}
    </div>
  );
};

export default ColorPicker;
