import { Checkbox, CheckboxGroupProps } from "@nextui-org/react";
import { ControllerFieldState } from "react-hook-form";
import { FaAsterisk } from "react-icons/fa6";

import { Options } from "@/types/options/options-data-types";

type CheckboxGroupFormProps = {
  fieldProps?: any;
  fieldState?: ControllerFieldState;
  options: Options;
  secondaryLabel?: string;
  onSelectionChange?: (value: number[]) => void;
  control?: any;
  name?: string;
};

type CheckboxGroupComponentProps = CheckboxGroupProps & CheckboxGroupFormProps;

function CheckboxGroup({
  fieldProps,
  fieldState,
  label,
  secondaryLabel,
  options,
  isInvalid,
  size,
  isRequired = true,
  classNames = {
    base: "",
    wrapper: `text-sm font-noto ${
      fieldState?.invalid || isInvalid ? "text-black" : ""
    }`,
    label:
      "text-start text-sm font-bold text-black tracking-tight font-inter ms-2",
    description:
      "font-inter font-regular text-[12px] text-gray-500 leading-tight",
  },
  value,
  onSelectionChange,
  name,
  isDisabled,
}: CheckboxGroupComponentProps) {
  const inputName = fieldProps?.name ?? name ?? label?.toString();
  const selectedValues = Array.from(
    new Set(
      (fieldProps ? (fieldProps.value ?? []) : (value ?? []))
        .map(Number)
        .filter(Number.isFinite),
    ),
  );
  const selectedValueSet = new Set(selectedValues);
  const hasError = fieldState?.invalid ?? isInvalid;
  const labelId = `${inputName}-label`;
  const descriptionId = `${inputName}-description`;

  const handleValueChange = (optionId: number, isSelected: boolean) => {
    const nextSelectedValues = new Set(selectedValues);

    if (isSelected) {
      nextSelectedValues.add(optionId);
    } else {
      nextSelectedValues.delete(optionId);
    }

    const nextValues = options
      .filter((option) => nextSelectedValues.has(option.id))
      .map((option) => option.id);

    fieldProps?.onChange(nextValues);
    onSelectionChange?.(nextValues);
  };

  return (
    <div
      aria-describedby={secondaryLabel ? descriptionId : undefined}
      aria-labelledby={labelId}
      className={`flex flex-col gap-1 ${classNames?.base || ""}`}
      id={inputName}
      role="group"
    >
      <span
        className={`block text-sm font-bold text-black tracking-tight font-inter pb-2 ${
          classNames?.label || ""
        }`}
        id={labelId}
      >
        {label}{" "}
        {isRequired && (
          <>
            <FaAsterisk
              aria-hidden
              className="text-red-600 inline-block size-2 mb-2"
              focusable="false"
            />
            <span className="sr-only">required</span>
          </>
        )}
      </span>
      <div className={`flex flex-col gap-2 ${classNames?.wrapper || ""}`}>
        {secondaryLabel && (
          <span
            className="text-xs text-gray-500 mt-0 font-inter pb-2"
            id={descriptionId}
          >
            {secondaryLabel}
          </span>
        )}
        {options.map((option, index) => {
          return (
            <div key={option.id} className="flex justify-between ms-1">
              <Checkbox
                ref={index === 0 ? fieldProps?.ref : undefined}
                disableAnimation
                color="default"
                isDisabled={isDisabled}
                isInvalid={hasError}
                isSelected={selectedValueSet.has(option.id)}
                name={inputName}
                radius="sm"
                size={size}
                value={option.id.toString()}
                onBlur={fieldProps?.onBlur}
                onValueChange={(isSelected) =>
                  handleValueChange(option.id, isSelected)
                }
              >
                {option.title}
              </Checkbox>
            </div>
          );
        })}
      </div>
    </div>
  );
}

export default CheckboxGroup;
