// Android Compose emitter — consumes a DTCG token object and produces three
// files: Theme.kt (Kotlin Compose), colors.xml, and dimens.xml.

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);
  }
}

// "semantic.color.action.primary" → "action.primary" → "ActionPrimary"
function pascalFromPath(path) {
  const parts = path.split('.');
  const trimmed = parts.slice(1); // drop root (primitive/semantic)
  let segs;
  if (trimmed[0] === 'color' && trimmed.length >= 3) {
    segs = trimmed.slice(1);
  } else {
    segs = trimmed;
  }
  return segs
    .map((s) => s.charAt(0).toUpperCase() + s.slice(1))
    .join('')
    .replace(/[^a-zA-Z0-9]/g, '');
}

// "semantic.color.action.primary" → "action_primary"
function snakeFromPath(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) => s.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase())
    .join('_')
    .replace(/[^a-z0-9_]/g, '');
}

// Normalize "#rgb"/"#rrggbb"/"#aarrggbb" to "FFRRGGBB" (alpha-first, uppercase).
function hexToArgb(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 `FF${h.toUpperCase()}`;
  if (h.length === 8 && /^[0-9a-fA-F]{8}$/.test(h)) return 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;
}

function collectColors(tokens) {
  const entries = [];
  const sem = tokens?.semantic?.color;
  if (sem) {
    for (const leaf of walkLeaves(sem, 'semantic.color')) {
      if (leaf.token.$type !== 'color') continue;
      const resolved = resolveRef(tokens, leaf.path);
      const argb = hexToArgb(resolved);
      if (!argb) continue;
      entries.push({ path: leaf.path, argb });
    }
  }
  const prim = tokens?.primitive?.color;
  if (prim) {
    for (const leaf of walkLeaves(prim, 'primitive.color')) {
      if (leaf.token.$type !== 'color') continue;
      const resolved = resolveRef(tokens, leaf.path);
      const argb = hexToArgb(resolved);
      if (!argb) continue;
      entries.push({ path: leaf.path, argb });
    }
  }
  return entries;
}

function collectDimensions(tokens) {
  const entries = [];
  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;
    entries.push({ path: `primitive.spacing.${key}`, value: n });
  }
  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;
    entries.push({ path: `primitive.radius.${key}`, value: n });
  }
  return entries;
}

function buildThemeKt(tokens, colors, dims) {
  const source = tokens?.$metadata?.source || '';
  const lines = [];
  lines.push(`// Generated by designlang v${HEADER_VERSION}`);
  if (source) lines.push(`// Source: ${source}`);
  lines.push('package com.designlang.tokens');
  lines.push('');
  lines.push('import androidx.compose.ui.graphics.Color');
  lines.push('import androidx.compose.ui.unit.dp');
  lines.push('');
  lines.push('object DesignTokens {');
  for (const { path, argb } of colors) {
    lines.push(`    val ${pascalFromPath(path)} = Color(0x${argb})`);
  }
  for (const { path, value } of dims) {
    lines.push(`    val ${pascalFromPath(path)} = ${value}.dp`);
  }
  lines.push('}');
  return lines.join('\n') + '\n';
}

function buildColorsXml(colors) {
  const lines = ['<?xml version="1.0" encoding="utf-8"?>', '<resources>'];
  for (const { path, argb } of colors) {
    lines.push(`    <color name="${snakeFromPath(path)}">#${argb}</color>`);
  }
  lines.push('</resources>');
  return lines.join('\n') + '\n';
}

function buildDimensXml(dims) {
  const lines = ['<?xml version="1.0" encoding="utf-8"?>', '<resources>'];
  for (const { path, value } of dims) {
    lines.push(`    <dimen name="${snakeFromPath(path)}">${value}dp</dimen>`);
  }
  lines.push('</resources>');
  return lines.join('\n') + '\n';
}

export function formatAndroidCompose(tokens) {
  const colors = collectColors(tokens);
  const dims = collectDimensions(tokens);
  return {
    'Theme.kt': buildThemeKt(tokens, colors, dims),
    'colors.xml': buildColorsXml(colors),
    'dimens.xml': buildDimensXml(dims),
  };
}
