import { type VariantProps, vcn } from "@pswui-lib";
import React from "react";

const checkboxColors = {
  background: {
    default: "bg-neutral-200 dark:bg-neutral-700",
    hover: "hover:bg-neutral-300 dark:hover:bg-neutral-600",
    checked:
      "has-[input[type=checkbox]:checked]:bg-neutral-300 dark:has-[input[type=checkbox]:checked]:bg-neutral-400",
    checkedHover:
      "has-[input[type=checkbox]:checked]:hover:bg-neutral-400 dark:has-[input[type=checkbox]:checked]:hover:bg-neutral-300",
    disabled:
      'has-[input[type="checkbox"]:disabled]:bg-neutral-100 dark:has-[input[type="checkbox"]:disabled]:bg-neutral-800',
    disabledHover:
      "has-[input[type='checkbox']:disabled]:hover:bg-neutral-100 dark:has-[input[type='checkbox']:disabled]:hover:bg-neutral-800",
    disabledChecked:
      "has-[input[type='checkbox']:disabled:checked]:bg-neutral-300 dark:has-[input[type='checkbox']:disabled:checked]:bg-neutral-700",
    disabledCheckedHover:
      "has-[input[type='checkbox']:disabled:checked]:hover:bg-neutral-300 dark:has-[input[type='checkbox']:disabled:checked]:hover:bg-neutral-700",
  },
};

const [checkboxVariant, resolveCheckboxVariantProps] = vcn({
  base: `inline-block rounded-md ${checkboxColors.background.disabled} ${checkboxColors.background.default} ${checkboxColors.background.hover} ${checkboxColors.background.checked} ${checkboxColors.background.checkedHover} ${checkboxColors.background.disabledChecked} ${checkboxColors.background.disabledCheckedHover} has-[input[type="checkbox"]:disabled]:cursor-not-allowed transition-colors duration-150 ease-in-out`,
  variants: {
    size: {
      base: "size-[1em] p-0 [&>svg]:size-[1em]",
      md: "size-[1.5em] p-0.5 [&>svg]:size-[1.25em]",
      lg: "size-[1.75em] p-1 [&>svg]:size-[1.25em]",
    },
  },
  defaults: {
    size: "md",
  },
});

interface CheckboxProps
  extends VariantProps<typeof checkboxVariant>,
    Omit<
      React.ComponentPropsWithoutRef<"input">,
      "type" | "className" | "size"
    > {}

const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
  (props, ref) => {
    const [variantProps, otherPropsCompressed] =
      resolveCheckboxVariantProps(props);
    const {
      defaultChecked,
      checked: propChecked,
      onChange,
      ...otherPropsExtracted
    } = otherPropsCompressed;

    // internally handles checked, so we can use checked value without prop
    const [checked, setChecked] = React.useState(defaultChecked ?? false);
    React.useEffect(() => {
      if (typeof propChecked === "boolean") {
        setChecked(propChecked);
      }
    }, [propChecked]);

    const internalRef = React.useRef<HTMLInputElement | null>(null);

    return (
      <>
        <label className={checkboxVariant(variantProps)}>
          <input
            {...otherPropsExtracted}
            defaultChecked={defaultChecked}
            checked={
              typeof defaultChecked === "boolean"
                ? undefined
                : checked /* should be either uncontrolled (defaultChecked set) or controlled (checked set) */
            }
            onChange={(e) => {
              setChecked(e.currentTarget.checked);
              if (onChange) {
                onChange(e);
              }
            }}
            type="checkbox"
            className="hidden"
            ref={(el) => {
              internalRef.current = el;
              if (typeof ref === "function") {
                ref(el);
              } else if (ref) {
                ref.current = el;
              }
            }}
          />
        </label>
      </>
    );
  },
);
Checkbox.displayName = "Checkbox";

export { Checkbox };