"use client";

import { ChevronUpIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import { ILabelValue } from "@/types/shared";
import { useEffect, useId, useState, type ChangeEvent } from "react";
import {
  type FieldErrors,
  type FieldValues,
  type Path,
  type UseFormRegister,
  type UseFormRegisterReturn,
} from "react-hook-form";

type PropsType<T extends FieldValues> = {
  name: Path<T>;
  label: string;
  items: ILabelValue[];
  prefixIcon?: React.ReactNode;
  onChange?: (e: ChangeEvent<HTMLSelectElement>) => void;
  className?: string;
  register?: UseFormRegister<T>;
  errors?: FieldErrors<T>;
  required?: boolean;
  clearable?: boolean;
  onClear?: () => void;
  value?: string;
} & (
  | { placeholder?: string; defaultValue?: string }
  | { placeholder: string; defaultValue?: string }
) &
  Partial<UseFormRegisterReturn>;

export function Select<T extends FieldValues>({
  items,
  label,
  defaultValue,
  placeholder,
  prefixIcon,
  className,
  name,
  register,
  errors,
  required,
  onChange,
  onBlur,
  ref,
  clearable = false,
  onClear,
  value: controlledValue,
  ...props
}: PropsType<T>) {
  const id = useId();

  const [isOptionSelected, setIsOptionSelected] = useState(!!defaultValue);
  const [value, setValue] = useState(defaultValue || "");
  const error = errors && errors[name];

  useEffect(() => {
    if (controlledValue !== undefined) {
      setValue(controlledValue);
      setIsOptionSelected(!!controlledValue);
    }
  }, [controlledValue]);

  const handleClear = () => {
    if (controlledValue === undefined) {
      setValue("");
    }
    setIsOptionSelected(false);
    onClear?.();
    if (onChange) {
      const event = {
        target: { value: "", name },
      } as unknown as ChangeEvent<HTMLSelectElement>;
      onChange(event);
    }
  };

  return (
    <div className={cn("space-y-3", className)}>
      <label
        htmlFor={id}
        className="block text-body-sm font-medium capitalize text-dark dark:text-white"
      >
        {label}
        {required && <span className="ml-1 select-none text-error">*</span>}
      </label>

      <div className="relative">
        {prefixIcon && (
          <div className="absolute left-4 top-1/2 -translate-y-1/2">
            {prefixIcon}
          </div>
        )}

        <select
          id={id}
          name={name}
          ref={ref}
          value={value}
          onChange={(e) => {
            if (controlledValue === undefined) {
              setValue(e.target.value);
            }
            setIsOptionSelected(!!e.target.value);
            onChange?.(e);
          }}
          onBlur={onBlur}
          className={cn(
            "w-full appearance-none rounded-lg border border-stroke bg-transparent px-5.5 py-3 outline-none transition focus:border-primary active:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary [&>option]:text-dark-5 dark:[&>option]:text-dark-6",
            isOptionSelected && "text-dark dark:text-white",
            error && "border-red focus:border-red dark:border-red",
            prefixIcon && "pl-11.5",
            clearable && value && "pr-20",
          )}
        >
          {placeholder && (
            <option value="" disabled>
              {placeholder}
            </option>
          )}

          {items.map((item) => (
            <option key={item.value} value={item.value}>
              {item.label}
            </option>
          ))}
        </select>

        {clearable && value && (
          <button
            type="button"
            onClick={handleClear}
            className="absolute right-10 top-1/2 -translate-y-1/2 text-dark-5 hover:text-dark dark:text-dark-6 dark:hover:text-white"
          >
            <svg
              width="16"
              height="16"
              viewBox="0 0 16 16"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M12 4L4 12M4 4L12 12"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
            </svg>
          </button>
        )}

        <ChevronUpIcon className="pointer-events-none absolute right-4 top-1/2 -translate-y-1/2 rotate-180" />
      </div>

      {error && (
        <p className="text-red mt-1.5 text-sm">{error.message as string}</p>
      )}
    </div>
  );
}
