import type { JSX } from "solid-js";
import { createEffect, splitProps } from "solid-js";
import { createControllableSignal } from "../../primitives/create-controllable-signal";

/** Represents all three states a checkbox can be in. */
export type CheckedState = boolean | "indeterminate";

export interface CheckboxProps
  extends Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, "onChange"> {
  /** Controlled checked state. */
  checked?: CheckedState;
  /** Default checked state (uncontrolled). @default false */
  defaultChecked?: CheckedState;
  /** Called when checked state changes. */
  onCheckedChange?: (checked: CheckedState) => void;
  /** Native form field name — renders a hidden checkbox input. */
  name?: string;
  /** Value submitted with the form when checked. @default "on" */
  value?: string;
  required?: boolean;
  children?: JSX.Element;
}

/**
 * A tri-state checkbox control supporting checked, unchecked, and indeterminate.
 * Click cycle: indeterminate → checked → unchecked → checked.
 */
export function Checkbox(props: CheckboxProps): JSX.Element {
  const [local, rest] = splitProps(props, [
    "checked",
    "defaultChecked",
    "onCheckedChange",
    "disabled",
    "required",
    "name",
    "value",
    "children",
  ]);

  const [isChecked, setChecked] = createControllableSignal<CheckedState>({
    value: () => local.checked,
    defaultValue: () => local.defaultChecked ?? false,
    onChange: local.onCheckedChange,
  });

  const ariaChecked = (): boolean | "mixed" => {
    const c = isChecked();
    return c === "indeterminate" ? "mixed" : c;
  };

  const dataState = (): string => {
    const c = isChecked();
    if (c === "indeterminate") return "indeterminate";
    return c ? "checked" : "unchecked";
  };

  return (
    <button
      type="button"
      role="checkbox"
      aria-checked={ariaChecked()}
      aria-required={local.required || undefined}
      data-state={dataState()}
      disabled={local.disabled}
      {...rest}
      onClick={() => {
        if (!local.disabled) {
          const current = isChecked();
          setChecked(current === "indeterminate" ? true : !current);
        }
      }}
    >
      {local.children}
      {local.name && (
        <input
          type="checkbox"
          aria-hidden="true"
          tabIndex={-1}
          name={local.name}
          value={local.value ?? "on"}
          checked={isChecked() === true}
          ref={(el) => {
            createEffect(() => {
              el.indeterminate = isChecked() === "indeterminate";
            });
          }}
          style={{ display: "none" }}
        />
      )}
    </button>
  );
}
