import type { JSX } from "solid-js";
import { createSignal, splitProps } from "solid-js";
import { ToggleGroupContextProvider, type ToggleGroupContextValue } from "./toggle-group-context";

type SingleProps = {
  type: "single";
  value?: string;
  defaultValue?: string;
  onValueChange?: (value: string | undefined) => void;
};

type MultipleProps = {
  type: "multiple";
  value?: string[];
  defaultValue?: string[];
  onValueChange?: (value: string[]) => void;
};

export type ToggleGroupRootProps = (SingleProps | MultipleProps) & {
  disabled?: boolean;
  children: JSX.Element;
} & JSX.HTMLAttributes<HTMLDivElement>;

/**
 * A group of toggle buttons. In "single" mode only one can be active at a time.
 * In "multiple" mode any number can be active simultaneously.
 */
export function ToggleGroupRoot(props: ToggleGroupRootProps): JSX.Element {
  // Cast to access discriminated union fields together
  const [local, rest] = splitProps(
    props as ToggleGroupRootProps & { type: "single" | "multiple" },
    ["type", "value", "defaultValue", "onValueChange", "disabled", "children"],
  );

  // Normalize to string[] internally. Use createSignal since the union type
  // is complex to thread through createControllableSignal generics safely.
  const getInitialValue = (): string[] => {
    const dv = local.defaultValue;
    if (dv === undefined) return [];
    return local.type === "multiple" ? (dv as string[]) : [dv as string];
  };

  const [pressedValues, setPressedValues] = createSignal<string[]>(getInitialValue());

  // Sync external controlled value
  const controlled = (): string[] | undefined => {
    const v = local.value;
    if (v === undefined) return undefined;
    return local.type === "multiple" ? (v as string[]) : v != null ? [v as string] : [];
  };

  const getValues = (): string[] => controlled() ?? pressedValues();

  const ctx: ToggleGroupContextValue = {
    isPressed: (value) => getValues().includes(value),
    onItemPress: (value) => {
      const current = getValues();
      let next: string[];
      if (local.type === "single") {
        next = current.includes(value) ? [] : [value];
      } else {
        next = current.includes(value) ? current.filter((v) => v !== value) : [...current, value];
      }
      // Only update internal state when uncontrolled
      if (controlled() === undefined) {
        setPressedValues(next);
      }
      // Call onChange
      if (local.type === "multiple") {
        (local.onValueChange as ((v: string[]) => void) | undefined)?.(next);
      } else {
        (local.onValueChange as ((v: string | undefined) => void) | undefined)?.(next[0]);
      }
    },
    disabled: () => local.disabled ?? false,
  };

  return (
    <ToggleGroupContextProvider value={ctx}>
      <div data-disabled={local.disabled || undefined} {...rest}>
        {local.children}
      </div>
    </ToggleGroupContextProvider>
  );
}
