// Flutter Dart emitter — consumes a DTCG token object and emits a Dart file
// with a DesignTokens class and a buildDesignlangTheme() ThemeData helper.

import { resolveRef } from './_token-ref.js';

const HEADER_VERSION = '7.0.0';

function* walkLeaves(node, prefix) {
  if (node == null || typeof node !== 'object') return;
  if ('$value' in node && '$type' in node) {
    yield { path: prefix, token: node };
    return;
  }
  for (const key of Object.keys(node)) {
    yield* walkLeaves(node[key], prefix ? `${prefix}.${key}` : key);
  }
}

function camelFromPath(path) {
  const parts = path.split('.');
  const trimmed = parts.slice(1);
  let segs;
  if (trimmed[0] === 'color' && trimmed.length >= 3) {
    segs = trimmed.slice(1);
  } else {
    segs = trimmed;
  }
  return segs
    .map((s, i) => (i === 0 ? s : s.charAt(0).toUpperCase() + s.slice(1)))
    .join('')
    .replace(/[^a-zA-Z0-9]/g, '');
}

function hexToDartArgb(hex) {
  if (typeof hex !== 'string') return null;
  let h = hex.trim().replace(/^#/, '');
  if (h.length === 3) h = h.split('').map((c) => c + c).join('');
  if (h.length === 6 && /^[0-9a-fA-F]{6}$/.test(h)) return `0xFF${h.toUpperCase()}`;
  if (h.length === 8 && /^[0-9a-fA-F]{8}$/.test(h)) return `0x${h.toUpperCase()}`;
  return null;
}

function dimensionToNumber(value) {
  if (typeof value === 'number') return value;
  if (typeof value !== 'string') return null;
  const m = value.match(/^(-?\d+(?:\.\d+)?)(px|pt|dp|rem|em)?$/);
  if (!m) return null;
  const n = parseFloat(m[1]);
  if (m[2] === 'rem' || m[2] === 'em') return n * 16;
  return n;
}

export function formatFlutterDart(tokens) {
  const source = tokens?.$metadata?.source || '';
  const lines = [];
  lines.push(`// Generated by designlang v${HEADER_VERSION}`);
  if (source) lines.push(`// Source: ${source}`);
  lines.push("import 'package:flutter/material.dart';");
  lines.push('');
  lines.push('class DesignTokens {');
  lines.push('  DesignTokens._();');
  lines.push('');

  // Semantic colors
  const semColor = tokens?.semantic?.color;
  const semEntries = [];
  if (semColor) {
    lines.push('  // Semantic');
    for (const leaf of walkLeaves(semColor, 'semantic.color')) {
      if (leaf.token.$type !== 'color') continue;
      const resolved = resolveRef(tokens, leaf.path);
      const argb = hexToDartArgb(resolved);
      if (!argb) continue;
      const name = camelFromPath(leaf.path);
      lines.push(`  static const Color ${name} = Color(${argb});`);
      semEntries.push({ name, path: leaf.path });
    }
  }

  // Primitive spacing
  const spacing = tokens?.primitive?.spacing || {};
  for (const key of Object.keys(spacing)) {
    const tok = spacing[key];
    if (!tok || tok.$type !== 'dimension') continue;
    const n = dimensionToNumber(resolveRef(tokens, `primitive.spacing.${key}`));
    if (n == null) continue;
    lines.push(`  static const double ${camelFromPath(`primitive.spacing.${key}`)} = ${n};`);
  }

  // Primitive radius
  const radius = tokens?.primitive?.radius || {};
  for (const key of Object.keys(radius)) {
    const tok = radius[key];
    if (!tok || tok.$type !== 'dimension') continue;
    const n = dimensionToNumber(resolveRef(tokens, `primitive.radius.${key}`));
    if (n == null) continue;
    lines.push(`  static const double ${camelFromPath(`primitive.radius.${key}`)} = ${n};`);
  }

  // Primitive colors for direct use
  const primColor = tokens?.primitive?.color;
  if (primColor) {
    lines.push('');
    lines.push('  // Primitive palette');
    for (const leaf of walkLeaves(primColor, 'primitive.color')) {
      if (leaf.token.$type !== 'color') continue;
      const resolved = resolveRef(tokens, leaf.path);
      const argb = hexToDartArgb(resolved);
      if (!argb) continue;
      lines.push(`  static const Color ${camelFromPath(leaf.path)} = Color(${argb});`);
    }
  }

  lines.push('}');
  lines.push('');

  // ThemeData helper
  const hasActionPrimary = semEntries.some((e) => e.name === 'actionPrimary');
  const hasSurfaceDefault = semEntries.some((e) => e.name === 'surfaceDefault');
  lines.push('ThemeData buildDesignlangTheme() {');
  lines.push('  return ThemeData(');
  lines.push('    colorScheme: const ColorScheme.light(');
  if (hasActionPrimary) lines.push('      primary: DesignTokens.actionPrimary,');
  if (hasSurfaceDefault) lines.push('      surface: DesignTokens.surfaceDefault,');
  lines.push('    ),');
  lines.push('  );');
  lines.push('}');

  return lines.join('\n') + '\n';
}
