/**
 * Checkbox Component Generator
 *
 * Generates a high-quality Checkbox ComponentSet in Figma matching the code implementation.
 *
 * Component Structure (from checkbox.tsx):
 * - Outer container: horizontal layout with gap-2 (8px)
 * - Checkbox box: 16x16, rounded-sm (2px), with ring border
 * - Label text: text-base font-medium text-kumo-default
 *
 * Properties:
 * - state: unchecked, checked, indeterminate
 * - variant: default, error
 * - disabled: true, false
 *
 * Reads all definitions from component-registry.json (the source of truth).
 * Uses the `styling` section for Figma-specific metadata (dimensions, icons, state tokens).
 *
 * @see packages/kumo/src/components/checkbox/checkbox.tsx
 */

import {
  bindFillToVariable,
  bindStrokeToVariable,
  getVariableByName,
  createModeSection,
  createTextNode,
  createRowLabel,
  createColumnHeaders,
  bindTextColorToVariable,
  BORDER_RADIUS,
  FONT_SIZE,
  SECTION_PADDING,
  SECTION_GAP,
  GRID_LAYOUT,
  FALLBACK_VALUES,
  SECTION_LAYOUT,
  SECTION_TITLE,
  OPACITY,
  SPACING,
  VAR_NAMES,
} from "./shared";
import themeData from "../generated/theme-data.json";
import { createIconInstance, bindIconColor } from "./icon-utils";
import { logInfo } from "../logger";

// Import variant data from the registry (generated by build:ai-metadata)
import registry from "@cloudflare/kumo/ai/component-registry.json";

// Extract props and styling from registry
const checkboxComponent = registry.components.Checkbox;
const checkboxProps = checkboxComponent.props;
const checkboxStyling = checkboxComponent.styling;

const variantProp = checkboxProps.variant as {
  values: string[];
  classes: Record<string, string>;
  descriptions: Record<string, string>;
  stateClasses?: Record<string, Record<string, string>>;
  default: string;
};

/**
 * State type for checkbox
 */
type CheckboxState = "unchecked" | "checked" | "indeterminate";

/**
 * Checkbox states (derived from styling.states in registry)
 */
const CHECKBOX_STATES: CheckboxState[] = [
  "unchecked",
  "checked",
  "indeterminate",
];

/**
 * TESTABLE EXPORTS - Pure functions that return intermediate data
 * These functions compute data without calling Figma APIs, enabling snapshot tests.
 */

/**
 * Get variant configuration from registry
 */
export function getCheckboxVariantConfig() {
  return {
    values: variantProp.values,
    classes: variantProp.classes,
    descriptions: variantProp.descriptions,
    stateClasses: variantProp.stateClasses || {},
    default: variantProp.default,
  };
}

/**
 * Get styling configuration from registry
 * This is unique to Checkbox - it has a `styling` section with Figma-specific metadata
 */
export function getCheckboxStylingConfig() {
  return {
    dimensions: checkboxStyling.dimensions as string,
    borderRadius: checkboxStyling.borderRadius as string,
    baseTokens: checkboxStyling.baseTokens as string[],
    states: checkboxStyling.states as Record<string, string[]>,
    icons: checkboxStyling.icons as Array<{
      name: string;
      state: string;
      size: number;
    }>,
  };
}

/**
 * Get checkbox box size from styling dimensions
 * Parses "h-4 w-4" to extract 16px
 * Generated from: Tailwind spacing scale (4 = 16px)
 */
export function getCheckboxBoxSize(): number {
  // h-4 w-4 = 16px from Tailwind spacing scale
  return themeData.tailwind.spacing.scale["4"];
}

/**
 * Get icon size from styling
 */
export function getCheckboxIconSize(): number {
  const styling = getCheckboxStylingConfig();
  return styling.icons[0]?.size || FALLBACK_VALUES.iconSize.small;
}

/**
 * Get label gap (gap-2 = 8px)
 * Generated from: Tailwind spacing scale (2 = 8px)
 */
export function getCheckboxLabelGap(): number {
  // gap-2 = 8px from Tailwind spacing scale
  return SPACING.base;
}

/**
 * Get border radius from styling
 * Parses "rounded-sm" to 2px
 */
export function getCheckboxBorderRadius(): number {
  return BORDER_RADIUS.sm; // 2px
}

/**
 * Get background variable for a given state
 */
export function getCheckboxBgVariable(state: CheckboxState): string {
  const isActive = state === "checked" || state === "indeterminate";
  return isActive ? VAR_NAMES.color.contrast : VAR_NAMES.color.base;
}

/**
 * Get ring/border variable for a given variant
 */
export function getCheckboxRingVariable(variant: string): string {
  return variant === "error" ? VAR_NAMES.color.danger : VAR_NAMES.color.line;
}

/**
 * Get icon name for a given state
 */
export function getCheckboxIconName(
  state: CheckboxState,
): "ph-check" | "ph-minus" | null {
  if (state === "checked") return "ph-check";
  if (state === "indeterminate") return "ph-minus";
  return null;
}

/**
 * Get complete box configuration for a specific state/variant/disabled combination
 */
export function getCheckboxBoxConfig(
  state: CheckboxState,
  variant: string,
  disabled: boolean,
) {
  const iconName = getCheckboxIconName(state);

  return {
    state,
    variant,
    disabled,
    size: getCheckboxBoxSize(),
    borderRadius: getCheckboxBorderRadius(),
    bgVariable: getCheckboxBgVariable(state),
    ringVariable: getCheckboxRingVariable(variant),
    icon: iconName,
    iconSize: iconName ? getCheckboxIconSize() : null,
    // Icon uses text-kumo-inverse from checkbox.tsx
    iconColor: iconName ? "text-kumo-inverse" : null,
    opacity: disabled ? OPACITY.disabled : 1.0,
  };
}

/**
 * Get layout configuration for checkbox with label
 */
export function getCheckboxLayoutConfig() {
  return {
    layoutMode: "HORIZONTAL" as const,
    primaryAxisAlignItems: "MIN" as const,
    counterAxisAlignItems: "CENTER" as const,
    primaryAxisSizingMode: "AUTO" as const,
    counterAxisSizingMode: "AUTO" as const,
    itemSpacing: getCheckboxLabelGap(),
  };
}

/**
 * Get text configuration for label
 */
export function getCheckboxTextConfig() {
  return {
    fontSize: FONT_SIZE.base, // 14px from theme-kumo.css
    fontWeight: FALLBACK_VALUES.fontWeight.medium, // font-medium = 500
    textVariable: VAR_NAMES.text.default,
  };
}

/**
 * Get complete checkbox configuration for a specific combination
 */
export function getCheckboxCompleteConfig(
  state: CheckboxState,
  variant: string,
  disabled: boolean,
) {
  return {
    state,
    variant,
    disabled,
    boxConfig: getCheckboxBoxConfig(state, variant, disabled),
    layoutConfig: getCheckboxLayoutConfig(),
    textConfig: getCheckboxTextConfig(),
    stylingConfig: getCheckboxStylingConfig(),
    opacity: disabled ? OPACITY.disabled : 1.0,
  };
}

/**
 * Get all checkbox variant data (for snapshot testing)
 * Returns intermediate data before Figma API calls
 */
export function getAllCheckboxVariantData() {
  const variantConfig = getCheckboxVariantConfig();
  const stylingConfig = getCheckboxStylingConfig();
  const layoutConfig = getCheckboxLayoutConfig();
  const textConfig = getCheckboxTextConfig();

  // Generate all box configurations
  const boxConfigs: ReturnType<typeof getCheckboxBoxConfig>[] = [];
  for (let si = 0; si < CHECKBOX_STATES.length; si++) {
    const state = CHECKBOX_STATES[si];
    for (let vi = 0; vi < variantConfig.values.length; vi++) {
      const variant = variantConfig.values[vi];
      for (let di = 0; di < 2; di++) {
        const disabled = di === 1;
        boxConfigs.push(getCheckboxBoxConfig(state, variant, disabled));
      }
    }
  }

  return {
    variantConfig,
    stylingConfig,
    layoutConfig,
    textConfig,
    states: CHECKBOX_STATES,
    boxConfigs,
    constants: {
      boxSize: getCheckboxBoxSize(),
      iconSize: getCheckboxIconSize(),
      labelGap: getCheckboxLabelGap(),
      borderRadius: getCheckboxBorderRadius(),
    },
  };
}

// ============================================================================
// FIGMA GENERATION FUNCTIONS (use Figma APIs)
// ============================================================================

/**
 * Create the checkbox box (the 16x16 square with optional icon)
 */
function createCheckboxBox(
  state: CheckboxState,
  variant: string,
  _disabled: boolean,
): FrameNode {
  const boxConfig = getCheckboxBoxConfig(state, variant, _disabled);

  const box = figma.createFrame();
  box.name = "Checkbox Box";
  box.resize(boxConfig.size, boxConfig.size);

  // Auto-layout for centering icon
  box.layoutMode = "HORIZONTAL";
  box.primaryAxisAlignItems = "CENTER";
  box.counterAxisAlignItems = "CENTER";
  box.primaryAxisSizingMode = "FIXED";
  box.counterAxisSizingMode = "FIXED";

  // Border radius from config
  box.cornerRadius = boxConfig.borderRadius;

  // Background fill from config
  const bgVar = getVariableByName(boxConfig.bgVariable);
  if (bgVar) {
    bindFillToVariable(box, bgVar.id);
  }

  // Ring/border from config
  const ringVar = getVariableByName(boxConfig.ringVariable);
  if (ringVar) {
    bindStrokeToVariable(box, ringVar.id, 1);
  }

  // Add icon if needed
  if (boxConfig.icon && boxConfig.iconSize) {
    const iconInstance = createIconInstance(boxConfig.icon, boxConfig.iconSize);
    if (iconInstance) {
      bindIconColor(iconInstance, boxConfig.iconColor || "text-kumo-inverse");
      box.appendChild(iconInstance);
    }
  }

  return box;
}

/**
 * Create a single checkbox component with label
 */
async function createCheckboxComponent(
  state: CheckboxState,
  variant: string,
  disabled: boolean,
  labelText: string,
): Promise<ComponentNode> {
  const completeConfig = getCheckboxCompleteConfig(state, variant, disabled);
  const layoutConfig = completeConfig.layoutConfig;
  const textConfig = completeConfig.textConfig;

  const component = figma.createComponent();
  component.name =
    "state=" + state + ", variant=" + variant + ", disabled=" + disabled;

  const variantDesc = variantProp.descriptions[variant] || "";
  component.description = variantDesc;

  // Configure as horizontal auto-layout (checkbox + label)
  component.layoutMode = layoutConfig.layoutMode;
  component.primaryAxisAlignItems = layoutConfig.primaryAxisAlignItems;
  component.counterAxisAlignItems = layoutConfig.counterAxisAlignItems;
  component.primaryAxisSizingMode = layoutConfig.primaryAxisSizingMode;
  component.counterAxisSizingMode = layoutConfig.counterAxisSizingMode;
  component.itemSpacing = layoutConfig.itemSpacing;
  component.fills = [];

  // Create checkbox box
  const checkboxBox = createCheckboxBox(state, variant, disabled);
  component.appendChild(checkboxBox);

  // Create label text
  const label = await createTextNode(
    labelText,
    textConfig.fontSize,
    textConfig.fontWeight,
  );

  // Bind text color
  const textVar = getVariableByName(textConfig.textVariable);
  if (textVar) {
    bindTextColorToVariable(label, textVar.id);
  }

  component.appendChild(label);

  // Apply disabled state: opacity-50
  if (disabled) {
    component.opacity = completeConfig.opacity;
  }

  return component;
}

/**
 * Get a simple label for the checkbox (just "Label" since state is shown in column headers)
 */
function getCheckboxLabel(): string {
  return "Label";
}

/**
 * Generate Checkbox ComponentSet
 *
 * Layout:
 * - Column headers: Unchecked | Checked | Indeterminate
 * - Row 1: variant=default
 * - Row 2: variant=default, disabled=true
 * - Row 3: variant=error
 * - Row 4: variant=error, disabled=true
 *
 * @param page - Target page for components
 * @param startY - Y position to start placing sections
 * @returns The Y position after all sections
 */
export async function generateCheckboxComponents(
  page: PageNode,
  startY: number = 100,
): Promise<number> {
  figma.currentPage = page;

  const states = CHECKBOX_STATES;
  const variants = variantProp.values;

  // Generate all meaningful combinations
  const components: ComponentNode[] = [];

  // Track row labels: { y, text }
  const rowLabels: { y: number; text: string }[] = [];

  // Layout grid spacing
  const componentGap = 24;
  const rowGap = GRID_LAYOUT.rowGap.standard;
  const headerRowHeight = GRID_LAYOUT.headerRowHeight;

  const labelColumnWidth = GRID_LAYOUT.labelColumnWidth.medium;

  // Column headers for states
  const columnHeaderTexts = ["Unchecked", "Checked", "Indeterminate"];

  // Track original X positions for column headers (before combineAsVariants moves them)
  const columnXPositions: number[] = [];

  // Track layout - each scenario on its own row for readability
  let currentY = headerRowHeight; // Start below header row

  // Generate rows for each variant × disabled combination
  for (let vi = 0; vi < variants.length; vi++) {
    const variant = variants[vi];

    // Enabled row
    rowLabels.push({ y: currentY, text: "variant=" + variant });
    let currentX = labelColumnWidth;
    for (let si = 0; si < states.length; si++) {
      const state = states[si];
      const component = await createCheckboxComponent(
        state,
        variant,
        false,
        getCheckboxLabel(),
      );
      component.x = currentX;
      component.y = currentY;
      // Store original X positions from first row for column headers
      if (vi === 0) {
        columnXPositions.push(currentX);
      }
      currentX += component.width + componentGap;
      components.push(component);
    }
    currentY += rowGap;

    // Disabled row
    rowLabels.push({
      y: currentY,
      text: "variant=" + variant + ", disabled=true",
    });
    currentX = labelColumnWidth;
    for (let sdi = 0; sdi < states.length; sdi++) {
      const stateD = states[sdi];
      const componentD = await createCheckboxComponent(
        stateD,
        variant,
        true,
        getCheckboxLabel(),
      );
      componentD.x = currentX;
      componentD.y = currentY;
      currentX += componentD.width + componentGap;
      components.push(componentD);
    }
    currentY += rowGap;
  }

  // Combine into ComponentSet
  // @ts-ignore - combineAsVariants works at runtime
  const componentSet = figma.combineAsVariants(components, page);
  componentSet.name = "Checkbox";
  componentSet.description =
    "Checkbox component with state (unchecked/checked/indeterminate), variant (default/error), and disabled properties. Includes label text.";

  componentSet.layoutMode = "NONE";

  // Calculate content dimensions (add label column width and header row)
  const contentWidth = componentSet.width + labelColumnWidth;
  const contentHeight = componentSet.height + headerRowHeight;

  // Content Y offset to make room for title inside frame
  const contentYOffset = SECTION_TITLE.height;

  // Create light mode section
  const lightSection = createModeSection(page, "Checkbox", "light");
  lightSection.frame.resize(
    contentWidth + SECTION_PADDING * 2,
    contentHeight + SECTION_PADDING * 2 + contentYOffset,
  );

  // Create dark mode section
  const darkSection = createModeSection(page, "Checkbox", "dark");
  darkSection.frame.resize(
    contentWidth + SECTION_PADDING * 2,
    contentHeight + SECTION_PADDING * 2 + contentYOffset,
  );

  // Add title inside each frame

  // Move ComponentSet into light section frame
  lightSection.frame.appendChild(componentSet);
  componentSet.x = SECTION_PADDING + labelColumnWidth;
  componentSet.y = SECTION_PADDING + headerRowHeight + contentYOffset;

  // Build column headers with stored original positions
  let columnHeaders: { x: number; text: string }[] = [];
  for (let i = 0; i < columnXPositions.length; i++) {
    columnHeaders.push({
      x: columnXPositions[i] + SECTION_PADDING,
      text: columnHeaderTexts[i],
    });
  }

  // Add column headers to light section
  await createColumnHeaders(
    columnHeaders,
    SECTION_PADDING + contentYOffset,
    lightSection.frame,
  );

  // Add row labels to light section
  for (let li = 0; li < rowLabels.length; li++) {
    const labelData = rowLabels[li];
    const labelNode = await createRowLabel(
      labelData.text,
      SECTION_PADDING,
      SECTION_PADDING +
        contentYOffset +
        labelData.y +
        GRID_LAYOUT.labelVerticalOffset.sm, // Small offset to vertically center with checkbox
    );
    lightSection.frame.appendChild(labelNode);
  }

  // Create instances for dark section
  // Note: component.x/y are relative to ComponentSet after combineAsVariants
  // We need to add labelColumnWidth to match the light section layout
  for (let ci = 0; ci < components.length; ci++) {
    const comp = components[ci];
    const instance = comp.createInstance();
    instance.x = comp.x + SECTION_PADDING + labelColumnWidth;
    instance.y = comp.y + SECTION_PADDING + headerRowHeight + contentYOffset;
    darkSection.frame.appendChild(instance);
  }

  // Add column headers to dark section
  await createColumnHeaders(
    columnHeaders,
    SECTION_PADDING + contentYOffset,
    darkSection.frame,
  );

  // Add row labels to dark section
  for (let dli = 0; dli < rowLabels.length; dli++) {
    const darkLabelData = rowLabels[dli];
    const darkLabelNode = await createRowLabel(
      darkLabelData.text,
      SECTION_PADDING,
      SECTION_PADDING +
        contentYOffset +
        darkLabelData.y +
        GRID_LAYOUT.labelVerticalOffset.sm,
    );
    darkSection.frame.appendChild(darkLabelNode);
  }

  // Resize sections to fit content with padding
  const totalWidth = contentWidth + SECTION_PADDING * 2;
  const totalHeight = contentHeight + SECTION_PADDING * 2 + contentYOffset;

  lightSection.section.resizeWithoutConstraints(totalWidth, totalHeight);
  darkSection.section.resizeWithoutConstraints(totalWidth, totalHeight);

  // Position sections at startY (no title offset needed since title is inside)
  lightSection.frame.x = SECTION_LAYOUT.startX;
  lightSection.frame.y = startY;

  darkSection.frame.x =
    lightSection.frame.x + totalWidth + SECTION_LAYOUT.modeGap;
  darkSection.frame.y = startY;

  logInfo(
    "✅ Generated Checkbox ComponentSet with " +
      components.length +
      " variants (light + dark)",
  );

  return startY + totalHeight + SECTION_GAP;
}

/**
 * Exports for tests and backwards compatibility
 */
export const CHECKBOX_VARIANTS_EXPORT = variantProp.values;
export const CHECKBOX_STATES_EXPORT = CHECKBOX_STATES;
export const CHECKBOX_DISABLED_OPTIONS = [false, true];
