import type { JSX } from "solid-js";
import { createSignal, createUniqueId, splitProps } from "solid-js";
import { createControllableSignal } from "../../primitives/create-controllable-signal";
import { WizardContextProvider, type WizardContextValue } from "./wizard-context";
import type { WizardRootProps } from "./wizard.props";

/** Root container for the Wizard component. Manages step state and progression. */
export function WizardRoot(props: WizardRootProps): JSX.Element {
  const [local, rest] = splitProps(props, [
    "step",
    "defaultStep",
    "linear",
    "orientation",
    "onStepChange",
    "onComplete",
    "children",
  ]);

  const baseId = createUniqueId();
  const [completedSteps, setCompletedSteps] = createSignal<Set<number>>(new Set());
  const [stepCount, setStepCount] = createSignal(0);

  const [currentStep, setCurrentStep] = createControllableSignal<number>({
    value: () => local.step,
    defaultValue: () => local.defaultStep ?? 0,
    onChange: (v) => local.onStepChange?.(v),
  });

  const isLinear = () => local.linear ?? true;

  /** Registers a step and returns its index. Called by WizardStep on mount. */
  function registerStep(): number {
    const index = stepCount();
    setStepCount((n) => n + 1);
    return index;
  }

  /** Unregisters a step. Called by WizardStep on cleanup. */
  function unregisterStep(): void {
    setStepCount((n) => Math.max(0, n - 1));
  }

  /** Returns true if the given step index is reachable in the current mode. */
  function isStepReachable(index: number): boolean {
    if (!isLinear()) return true;
    if (index === 0) return true;
    const completed = completedSteps();
    for (let i = 0; i < index; i++) {
      if (!completed.has(i)) return false;
    }
    return true;
  }

  /** Navigate to a specific step if reachable. */
  function goToStep(index: number): void {
    if (isStepReachable(index)) setCurrentStep(index);
  }

  /** Mark current step complete and advance. Calls onComplete on last step. */
  function goToNext(): void {
    const current = currentStep();
    const total = stepCount();
    setCompletedSteps((prev) => {
      const next = new Set(prev);
      next.add(current);
      return next;
    });
    if (current >= total - 1) {
      local.onComplete?.();
      return;
    }
    setCurrentStep(current + 1);
  }

  /** Navigate to the previous step (always allowed). */
  function goToPrev(): void {
    const current = currentStep();
    if (current > 0) setCurrentStep(current - 1);
  }

  const ctx: WizardContextValue = {
    currentStep,
    completedSteps,
    totalSteps: stepCount,
    linear: isLinear,
    orientation: () => local.orientation ?? "horizontal",
    registerStep,
    unregisterStep,
    goToStep,
    goToNext,
    goToPrev,
    isStepReachable,
    baseId,
  };

  return (
    <WizardContextProvider value={ctx}>
      <div data-orientation={local.orientation ?? "horizontal"} {...rest}>
        {local.children}
      </div>
    </WizardContextProvider>
  );
}
