/**
 * Empty Component Generator
 *
 * Generates Empty components in Figma with size variants.
 * Reads variant definitions from component-registry.json (the source of truth).
 */

import {
  createTextNode,
  bindFillToVariable,
  bindStrokeToVariable,
  bindTextColorToVariable,
  getVariableByName,
  createModeSection,
  createRowLabel,
  SECTION_PADDING,
  SECTION_GAP,
  GRID_LAYOUT,
  SECTION_LAYOUT,
  SECTION_TITLE,
  FALLBACK_VALUES,
  FONT_SIZE,
  VAR_NAMES,
} from "./shared";
import { parseTailwindClasses } from "../parsers/tailwind-to-figma";
import { logInfo, logWarn } from "../logger";

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

const emptyComponent = registry.components.Empty;
const emptyProps = emptyComponent.props;
const sizeProp = emptyProps.size as {
  values: string[];
  classes: Record<string, string>;
  descriptions: Record<string, string>;
  default: string;
};

/**
 * Empty base styles from emptyVariants() in empty.tsx
 */
const EMPTY_BASE_STYLES =
  "flex w-full flex-col items-center rounded-xl border border-kumo-fill bg-kumo-control text-kumo-default";

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

/**
 * Get size configuration from registry
 */
export function getEmptySizeConfig() {
  return {
    values: sizeProp.values,
    classes: sizeProp.classes,
    descriptions: sizeProp.descriptions,
    default: sizeProp.default,
  };
}

/**
 * Get parsed base styles
 */
export function getEmptyParsedBaseStyles() {
  return parseTailwindClasses(EMPTY_BASE_STYLES);
}

/**
 * Get parsed styles for a specific size
 */
export function getEmptyParsedSizeStyles(size: string) {
  const classes = sizeProp.classes[size] || "";
  return {
    size,
    classes,
    description: sizeProp.descriptions[size] || "",
    parsed: parseTailwindClasses(classes),
  };
}

/**
 * Get icon configuration
 */
export function getEmptyIconConfig() {
  return {
    // Icon is database icon (48x48) with text-kumo-inactive color
    // iconSize uses FALLBACK_VALUES.iconSize.lg (size-12 = 48px from spacing scale)
    iconName: "ph-database",
    iconSize: FALLBACK_VALUES.iconSize.lg,
    iconColorToken: VAR_NAMES.text.inactive,
  };
}

/**
 * Get text configuration
 */
export function getEmptyTextConfig() {
  return {
    title: {
      text: "No data available",
      fontSize: themeData.tailwind.fontSize["2xl"], // 24px from Tailwind
      fontWeight: FALLBACK_VALUES.fontWeight.semiBold, // 600 from theme-data.json
      colorToken: VAR_NAMES.text.default,
    },
    description: {
      text: "There is no data to display at the moment. Try creating a new item to get started.",
      fontSize: FONT_SIZE.base, // 14px from theme-kumo.css
      fontWeight: FALLBACK_VALUES.fontWeight.normal, // 400 from theme-data.json
      maxWidth: 560, // FIGMA-SPECIFIC: max-w-140 layout width for Figma display (140 * 4px = 560px)
      colorToken: VAR_NAMES.text.strong,
      textAlign: "CENTER" as const,
    },
  };
}

/**
 * Get all size variant data (for snapshot testing)
 * Returns intermediate data before Figma API calls
 */
export function getAllEmptyData() {
  const baseStyles = getEmptyParsedBaseStyles();
  const config = getEmptySizeConfig();
  const iconConfig = getEmptyIconConfig();
  const textConfig = getEmptyTextConfig();

  return {
    baseStyles: {
      raw: EMPTY_BASE_STYLES,
      parsed: baseStyles,
    },
    sizes: config.values.map((size) => {
      const sizeData = getEmptyParsedSizeStyles(size);
      return {
        ...sizeData,
        // Layout calculations
        layout: {
          layoutMode: "VERTICAL",
          primaryAxisAlignItems: "CENTER",
          counterAxisAlignItems: "CENTER",
          paddingLeft: sizeData.parsed.paddingX ?? 40,
          paddingRight: sizeData.parsed.paddingX ?? 40,
          paddingTop: sizeData.parsed.paddingY ?? 64,
          paddingBottom: sizeData.parsed.paddingY ?? 64,
          itemSpacing: sizeData.parsed.gap ?? 24,
          cornerRadius: baseStyles.borderRadius ?? 12,
          primaryAxisSizingMode: "AUTO",
          counterAxisSizingMode: "FIXED",
          width: 600, // Fixed width for empty state container
        },
        // Color bindings
        colors: {
          fill: baseStyles.fillVariable || VAR_NAMES.color.control,
          stroke: baseStyles.strokeVariable || VAR_NAMES.color.fill,
          text: baseStyles.textVariable || VAR_NAMES.text.default,
        },
      };
    }),
    icon: iconConfig,
    text: textConfig,
  };
}

/**
 * Create a single Empty component with the specified size
 */
async function createEmptyComponent(size: string): Promise<ComponentNode> {
  const classes = sizeProp.classes[size] || "";
  const description = sizeProp.descriptions[size] || "";

  // Parse base styles and size-specific styles
  const baseStyles = parseTailwindClasses(EMPTY_BASE_STYLES);
  const sizeStyles = parseTailwindClasses(classes);

  // Create component
  const component = figma.createComponent();
  component.name = "size=" + size;
  component.description = description;

  // Set up auto-layout (vertical stack, centered)
  component.layoutMode = "VERTICAL";
  component.primaryAxisAlignItems = "CENTER";
  component.counterAxisAlignItems = "CENTER";

  // Apply padding with fallbacks
  if (sizeStyles.paddingX !== undefined) {
    component.paddingLeft = sizeStyles.paddingX;
    component.paddingRight = sizeStyles.paddingX;
  } else {
    logWarn("Empty: paddingX not found in sizeStyles, using fallback 40");
    component.paddingLeft = 40;
    component.paddingRight = 40;
  }

  if (sizeStyles.paddingY !== undefined) {
    component.paddingTop = sizeStyles.paddingY;
    component.paddingBottom = sizeStyles.paddingY;
  } else {
    logWarn("Empty: paddingY not found in sizeStyles, using fallback 64");
    component.paddingTop = 64;
    component.paddingBottom = 64;
  }

  // Apply gap with fallback
  if (sizeStyles.gap !== undefined) {
    component.itemSpacing = sizeStyles.gap;
  } else {
    logWarn("Empty: gap not found in sizeStyles, using fallback 24");
    component.itemSpacing = 24;
  }

  component.primaryAxisSizingMode = "AUTO";
  component.counterAxisSizingMode = "FIXED";
  component.resize(600, component.height); // Fixed width

  // Apply borderRadius with fallback
  if (baseStyles.borderRadius !== undefined) {
    component.cornerRadius = baseStyles.borderRadius;
  } else {
    logWarn("Empty: borderRadius not found in baseStyles, using fallback 12");
    component.cornerRadius = 12;
  }

  // Apply fill (background)
  if (baseStyles.fillVariable) {
    const fillVar = getVariableByName(baseStyles.fillVariable);
    if (fillVar) {
      bindFillToVariable(component, fillVar.id);
    }
  }

  // Apply border
  if (baseStyles.hasBorder && baseStyles.strokeVariable) {
    const strokeVar = getVariableByName(baseStyles.strokeVariable);
    if (strokeVar) {
      const strokeWeight = baseStyles.strokeWeight ?? 1;
      bindStrokeToVariable(component, strokeVar.id, strokeWeight);
    }
  }

  // Create icon placeholder (48x48 square representing ph-database icon)
  const iconFrame = figma.createFrame();
  iconFrame.name = "Icon";
  iconFrame.resize(48, 48);
  iconFrame.layoutMode = "HORIZONTAL";
  iconFrame.primaryAxisAlignItems = "CENTER";
  iconFrame.counterAxisAlignItems = "CENTER";
  iconFrame.fills = [];

  // Create icon circle (visual representation)
  const iconCircle = figma.createEllipse();
  iconCircle.name = "ph-database";
  iconCircle.resize(48, 48);
  const disabledVar = getVariableByName(VAR_NAMES.text.disabled);
  if (disabledVar) {
    bindFillToVariable(iconCircle, disabledVar.id);
  }

  iconFrame.appendChild(iconCircle);
  component.appendChild(iconFrame);

  // Create title text (use config values)
  const textConfig = getEmptyTextConfig();
  const titleNode = await createTextNode(
    textConfig.title.text,
    textConfig.title.fontSize,
    textConfig.title.fontWeight,
  );
  titleNode.name = "Title";
  const surfaceTextVar = getVariableByName(VAR_NAMES.text.default);
  if (surfaceTextVar) {
    bindTextColorToVariable(titleNode, surfaceTextVar.id);
  }
  component.appendChild(titleNode);

  // Create description text (wrapped in frame for width constraint)
  const descriptionFrame = figma.createFrame();
  descriptionFrame.name = "Description Container";
  descriptionFrame.resize(textConfig.description.maxWidth, 50); // FIGMA-SPECIFIC: max-w-140 layout width
  descriptionFrame.layoutMode = "HORIZONTAL";
  descriptionFrame.primaryAxisAlignItems = "CENTER";
  descriptionFrame.counterAxisAlignItems = "CENTER";
  descriptionFrame.primaryAxisSizingMode = "FIXED";
  descriptionFrame.counterAxisSizingMode = "AUTO";
  descriptionFrame.fills = [];

  const descriptionNode = await createTextNode(
    textConfig.description.text,
    textConfig.description.fontSize,
    textConfig.description.fontWeight,
  );
  descriptionNode.name = "Description";
  const labelTextVar = getVariableByName(VAR_NAMES.text.label);
  if (labelTextVar) {
    bindTextColorToVariable(descriptionNode, labelTextVar.id);
  }
  descriptionFrame.appendChild(descriptionNode);
  component.appendChild(descriptionFrame);

  return component;
}

/**
 * Generate Empty ComponentSet with size property
 *
 * Creates a single "Empty" ComponentSet with size variants derived from
 * component-registry.json. Creates both light and dark mode sections.
 *
 * @param startY - Y position to start placing the section
 * @returns The Y position after this section (for next section placement)
 */
export async function generateEmptyComponents(startY: number): Promise<number> {
  if (startY === undefined) startY = 100;

  // Get size keys from the registry
  const sizes = sizeProp.values;
  const components: ComponentNode[] = [];

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

  // Layout spacing - vertical layout with labels
  const rowGap = GRID_LAYOUT.rowGap.medium;
  const labelColumnWidth = GRID_LAYOUT.labelColumnWidth.medium;

  // Track position for laying out components vertically
  let currentY = 0;

  for (let i = 0; i < sizes.length; i++) {
    const size = sizes[i];
    const component = await createEmptyComponent(size);

    // Record row label
    rowLabels.push({ y: currentY, text: "size=" + size });

    // Position each component vertically with label offset
    component.x = labelColumnWidth;
    component.y = currentY;
    currentY += component.height + rowGap;
    components.push(component);
  }

  // Combine all variants into a single ComponentSet
  const componentSet = figma.combineAsVariants(components, figma.currentPage);
  componentSet.name = "Empty";
  componentSet.description = "Empty component with size variants";

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

  // Add contentYOffset for title space inside frame
  const contentYOffset = SECTION_TITLE.height;

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

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

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

  // Add section titles inside frames

  // Add row labels to light section
  for (const label of rowLabels) {
    const labelNode = await createRowLabel(
      label.text,
      SECTION_PADDING,
      SECTION_PADDING +
        contentYOffset +
        label.y +
        GRID_LAYOUT.labelVerticalOffset.xl, // Offset to align with component center
    );
    lightSection.frame.appendChild(labelNode);
  }

  // Create instances for dark section
  for (const component of components) {
    const instance = component.createInstance();
    instance.x = component.x + SECTION_PADDING + labelColumnWidth;
    instance.y = component.y + SECTION_PADDING + contentYOffset;
    darkSection.frame.appendChild(instance);
  }

  // Add row labels to dark section
  for (const label of rowLabels) {
    const labelNode = await createRowLabel(
      label.text,
      SECTION_PADDING,
      SECTION_PADDING +
        contentYOffset +
        label.y +
        GRID_LAYOUT.labelVerticalOffset.xl,
    );
    darkSection.frame.appendChild(labelNode);
  }

  // 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 side by side
  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 Empty ComponentSet with " +
      sizes.length +
      " sizes (light + dark)",
  );

  return startY + totalHeight + SECTION_GAP;
}
