/**
 * Link Component Generator
 *
 * Generates a single Link ComponentSet in Figma with variant property.
 * Reads variant definitions from component-registry.json (the source of truth).
 *
 * Link is a text-only component with three variants:
 * - inline: Default underlined link (text-primary) with semi-transparent underline
 * - current: Inherits color from parent (text-current) with semi-transparent underline
 * - plain: No underline decoration (text-primary)
 *
 * Underline opacity (from .link-current CSS class in kumo-binding.css):
 * - Light mode: 35% opacity
 * - Dark mode: 65% opacity
 * - Hover: 100% opacity (not shown in static Figma)
 */

import {
  createTextNode,
  getVariableByName,
  createModeSection,
  createRowLabel,
  bindTextColorToVariable,
  SECTION_PADDING,
  SECTION_GAP,
  GRID_LAYOUT,
  SECTION_LAYOUT,
  SECTION_TITLE,
  FONT_SIZE,
  VAR_NAMES,
  ColorMode,
} from "./shared";
import { logInfo } from "../logger";

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

// Type assertion needed because the JSON types may not include newly added components
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const linkComponent = (registry.components as any).Link as {
  props: {
    variant: {
      values: string[];
      classes: Record<string, string>;
      descriptions: Record<string, string>;
      default: string;
    };
  };
};
const linkProps = linkComponent.props;
const variantProp = linkProps.variant as {
  values: string[];
  classes: Record<string, string>;
  descriptions: Record<string, string>;
  default: string;
};

/**
 * 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 getLinkVariantConfig() {
  return {
    values: variantProp.values,
    classes: variantProp.classes,
    descriptions: variantProp.descriptions,
    default: variantProp.default,
  };
}

/**
 * Underline opacity values from .link-current CSS class
 * These match the color-mix values in kumo-binding.css
 */
const UNDERLINE_OPACITY = {
  light: 0.35, // color-mix(in oklch, currentColor 35%, transparent)
  dark: 0.65, // color-mix(in oklch, currentColor 65%, transparent)
} as const;

/**
 * Get parsed styles for a specific variant
 */
export function getLinkParsedVariantStyles(variant: string) {
  const classes = variantProp.classes[variant] || "";
  return {
    variant,
    classes,
    description: variantProp.descriptions[variant] || "",
    // Link uses text-primary or text-current classes
    hasUnderline: classes.includes("underline"),
    // Check if variant uses link-current class (has semi-transparent underline)
    hasLinkCurrentClass: classes.includes("link-current"),
    textColor: classes.includes("text-current") ? "current" : "primary",
  };
}

/**
 * Get all variant data (for snapshot testing)
 */
export function getAllLinkVariantData() {
  const config = getLinkVariantConfig();

  return {
    variants: config.values.map((variant) => {
      const variantData = getLinkParsedVariantStyles(variant);
      return {
        ...variantData,
        layout: {
          layoutMode: "HORIZONTAL",
          primaryAxisAlignItems: "MIN",
          counterAxisAlignItems: "MIN",
          primaryAxisSizingMode: "AUTO",
          counterAxisSizingMode: "AUTO",
        },
        text: {
          fontSize: FONT_SIZE.base, // Links use base font size
          fontWeight: 400, // Regular weight
        },
      };
    }),
  };
}

/**
 * Create a single Link component with the specified variant
 *
 * For variants with underlines (inline, current), we create a custom underline
 * as a separate line element to support the semi-transparent opacity that
 * matches the CSS implementation (.link-current class).
 *
 * @param variant - The variant name (inline, current, plain)
 * @param mode - Color mode for underline opacity (light = 35%, dark = 65%)
 */
async function createLinkComponent(
  variant: string,
  mode: ColorMode,
): Promise<ComponentNode> {
  const variantData = getLinkParsedVariantStyles(variant);

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

  // Set up auto-layout - vertical to stack text and underline
  component.layoutMode = "VERTICAL";
  component.primaryAxisAlignItems = "MIN";
  component.counterAxisAlignItems = "MIN";
  component.primaryAxisSizingMode = "AUTO";
  component.counterAxisSizingMode = "AUTO";
  component.itemSpacing = 0; // No gap - underline sits tight under text

  // No background for link components
  component.fills = [];

  // Create text node
  const textNode = await createTextNode("Link text", FONT_SIZE.base, 400);
  textNode.name = "Label";

  // Get the appropriate text color variable
  let textColorVar;
  if (variantData.textColor === "current") {
    // For "current" variant, use default text color in Figma demo
    textColorVar = getVariableByName(VAR_NAMES.text.default);
  } else {
    // For inline and plain, use link/brand color
    textColorVar = getVariableByName(VAR_NAMES.text.link);
  }

  // Apply text color
  if (textColorVar) {
    bindTextColorToVariable(textNode, textColorVar.id);
  }

  component.appendChild(textNode);

  // Create custom underline for variants that need it
  // We use a line instead of textDecoration to support opacity
  if (variantData.hasUnderline && variantData.hasLinkCurrentClass) {
    const underlineOpacity = UNDERLINE_OPACITY[mode];

    // Create underline as a thin rectangle
    const underline = figma.createRectangle();
    underline.name = "Underline";

    // FIGMA-SPECIFIC: Underline dimensions based on CSS decoration-[0.0625em]
    // At 14px font size, 0.0625em ≈ 0.875px, we round to 1px for Figma
    const underlineHeight = 1;

    // Set underline to fill width of text
    underline.resize(textNode.width, underlineHeight);

    // Apply color with opacity
    if (textColorVar) {
      const variable = figma.variables.getVariableById(textColorVar.id);
      if (variable) {
        let underlineFill: SolidPaint = {
          type: "SOLID",
          color: { r: 0, g: 0.5, b: 1 }, // Fallback
          opacity: underlineOpacity,
        };
        underlineFill = figma.variables.setBoundVariableForPaint(
          underlineFill,
          "color",
          variable,
        );
        underline.fills = [underlineFill];
      }
    }

    // Position underline with offset matching CSS underline-offset-[0.15em]
    // At 14px, 0.15em ≈ 2px offset from baseline
    // We use negative margin via the auto-layout gap to pull it up slightly
    component.itemSpacing = -2; // Pull underline up 2px to match offset

    component.appendChild(underline);
    // Must be set AFTER appending to an auto-layout parent
    underline.layoutSizingHorizontal = "FILL";
  } else if (variantData.hasUnderline) {
    // For underlined variants without .link-current, use standard decoration
    textNode.textDecoration = "UNDERLINE";
  }

  return component;
}

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

  figma.currentPage = page;

  // Get variant keys from the registry
  const variants = variantProp.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 < variants.length; i++) {
    const variant = variants[i];
    // Create component for light mode (ComponentSet will be in light section)
    const component = await createLinkComponent(variant, "light");

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

    // 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, page);
  componentSet.name = "Link";
  componentSet.description =
    "Link component with variant styles for navigation";

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

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

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

  // Create dark mode section
  const darkSection = createModeSection(page, "Link", "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 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.sm, // Small offset to vertically center with link text
    );
    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.sm,
    );
    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 at startY
  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 Link ComponentSet with " +
      variants.length +
      " variants (light + dark)",
  );

  return startY + totalHeight + SECTION_GAP;
}
