/**
 * Token generator — reads bytelyst.tokens.json, outputs 4 platform formats:
 *   1. CSS custom properties (tokens.css)
 *   2. TypeScript constants (tokens.ts)
 *   3. Kotlin object (MindLystTokens.kt) — for KMP shared module
 *   4. Swift structs (MindLystTheme.swift) — for iOS SwiftUI
 *
 * Output conventions match the hand-written originals in learning_multimodal_memory_agents:
 *   - Kotlin: SCREAMING_SNAKE_CASE, Palette/Dark/Light/BrainGradient/Typography/Motion/Layout
 *   - Swift:  Color(hex: UInt), dark/light prefixes, Gradient(colors:), MindLystMotion, Color ext
 *   - CSS:    [data-theme], --ml-fs-*, --ml-elevation-*, --ml-motion-*
 *
 * Usage: tsx scripts/generate.ts
 */

import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));
const tokensPath = resolve(__dirname, '../tokens/bytelyst.tokens.json');
const outDir = resolve(__dirname, '../generated');

mkdirSync(outDir, { recursive: true });

const tokens = JSON.parse(readFileSync(tokensPath, 'utf-8'));

// ── Helpers ──────────────────────────────────────────────────────────

function camelToKebab(str: string): string {
  return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
}

function camelToScreamingSnake(str: string): string {
  return str.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
}

function hexToUInt(hex: string): string {
  return `0x${hex.replace('#', '').toUpperCase()}`;
}

function capitalize(s: string): string {
  return s.charAt(0).toUpperCase() + s.slice(1);
}

// ── 1. CSS ───────────────────────────────────────────────────────────
function generateCSS(): string {
  const lines: string[] = [
    '/* Auto-generated from bytelyst.tokens.json — do not edit manually */',
    '',
    ':root,',
    '[data-theme="dark"] {',
  ];

  // Semantic colors (dark theme as default)
  for (const [key, value] of Object.entries(tokens.color.semantic.dark)) {
    lines.push(`  --ml-${camelToKebab(key)}: ${value};`);
  }
  lines.push('');

  // Typography
  for (const [key, value] of Object.entries(tokens.typography.fontFamily)) {
    // Swap single quotes → double quotes for CSS
    const cssVal = typeof value === 'string' ? value.replace(/'/g, '"') : value;
    lines.push(`  --ml-font-${key}: ${cssVal};`);
  }
  lines.push('');

  // Font sizes (--ml-fs-* to match existing convention)
  for (const [key, value] of Object.entries(tokens.typography.fontSize)) {
    lines.push(`  --ml-fs-${key}: ${value}px;`);
  }
  lines.push('');

  // Spacing
  for (const [key, value] of Object.entries(tokens.spacing)) {
    lines.push(`  --ml-space-${key}: ${value === 0 ? '0' : `${value}px`};`);
  }
  lines.push('');

  // Radius
  for (const [key, value] of Object.entries(tokens.radius)) {
    lines.push(`  --ml-radius-${key}: ${value}px;`);
  }
  lines.push('');

  // Elevation (--ml-elevation-* to match existing)
  for (const [key, value] of Object.entries(tokens.elevation)) {
    if (key === 'none') continue;
    lines.push(`  --ml-elevation-${key}: ${value};`);
  }
  lines.push('');

  // Motion
  for (const [key, value] of Object.entries(tokens.motion.duration)) {
    if (key === 'instant') continue; // not used in CSS
    lines.push(`  --ml-motion-${key}: ${value}ms;`);
  }
  lines.push(`  --ml-easing-standard: ${tokens.motion.easing.standard};`);

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

  // Light theme overrides
  lines.push('[data-theme="light"] {');
  for (const [key, value] of Object.entries(tokens.color.semantic.light)) {
    // Only emit overrides where light differs from dark
    const darkVal = tokens.color.semantic.dark[key];
    if (value !== darkVal) {
      lines.push(`  --ml-${camelToKebab(key)}: ${value};`);
    }
  }
  lines.push('}', '');

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

// ── 2. TypeScript ────────────────────────────────────────────────────
function generateTS(): string {
  return [
    '// Auto-generated from bytelyst.tokens.json — do not edit manually',
    '',
    `export const tokens = ${JSON.stringify(tokens, null, 2)} as const;`,
    '',
    'export type Tokens = typeof tokens;',
    '',
  ].join('\n');
}

// ── 3. Kotlin ────────────────────────────────────────────────────────
function generateKotlin(): string {
  const lines: string[] = [
    '// Auto-generated from bytelyst.tokens.json — do not edit manually',
    'package com.mindlyst.shared.theme',
    '',
    '/**',
    ' * Cross-platform design tokens from bytelyst.tokens.json.',
    ' * Single source of truth consumed by both Android (Compose) and iOS (SwiftUI).',
    ' */',
    'object MindLystTokens {',
    '',
  ];

  // ── Palette
  lines.push('    // ── Color Palette ────────────────────────────────────────────────');
  lines.push('    object Palette {');
  for (const [key, value] of Object.entries(tokens.color.palette.neutral)) {
    lines.push(
      `        const val NEUTRAL_${key} = 0xFF${(value as string).replace('#', '').toUpperCase()}`
    );
  }
  lines.push('');
  for (const [key, value] of Object.entries(tokens.color.palette.brand)) {
    lines.push(
      `        const val ${key.toUpperCase()} = 0xFF${(value as string).replace('#', '').toUpperCase()}`
    );
  }
  lines.push('    }', '');

  // ── Dark semantic
  lines.push('    // ── Semantic Colors (Dark Theme) ─────────────────────────────────');
  lines.push('    object Dark {');
  for (const [key, value] of Object.entries(tokens.color.semantic.dark)) {
    if (typeof value === 'string' && value.startsWith('#')) {
      lines.push(
        `        const val ${camelToScreamingSnake(key)} = 0xFF${value.replace('#', '').toUpperCase()}`
      );
    }
  }
  lines.push('    }', '');

  // ── Light semantic
  lines.push('    // ── Semantic Colors (Light Theme) ────────────────────────────────');
  lines.push('    object Light {');
  for (const [key, value] of Object.entries(tokens.color.semantic.light)) {
    if (typeof value === 'string' && value.startsWith('#')) {
      lines.push(
        `        const val ${camelToScreamingSnake(key)} = 0xFF${value.replace('#', '').toUpperCase()}`
      );
    }
  }
  lines.push('    }', '');

  // ── Brain gradients
  lines.push('    // ── Brain Identity Gradients ─────────────────────────────────────');
  lines.push('    data class BrainGradient(val from: Long, val to: Long)');
  lines.push('');
  for (const [name, grad] of Object.entries(tokens.color.brain) as [
    string,
    { from: string; to: string },
  ][]) {
    lines.push(
      `    val BRAIN_${name.toUpperCase()} = BrainGradient(from = 0xFF${grad.from.replace('#', '').toUpperCase()}, to = 0xFF${grad.to.replace('#', '').toUpperCase()})`
    );
  }
  lines.push('');

  // ── Spacing
  lines.push('    // ── Spacing (8pt grid) ───────────────────────────────────────────');
  lines.push('    object Spacing {');
  for (const [key, value] of Object.entries(tokens.spacing)) {
    lines.push(`        const val X${key} = ${value}`);
  }
  lines.push('    }', '');

  // ── Radius
  lines.push('    // ── Radius ───────────────────────────────────────────────────────');
  lines.push('    object Radius {');
  for (const [key, value] of Object.entries(tokens.radius)) {
    lines.push(`        const val ${key.toUpperCase()} = ${value}`);
  }
  lines.push('    }', '');

  // ── Typography
  lines.push('    // ── Typography ───────────────────────────────────────────────────');
  lines.push('    object Typography {');
  for (const [key, value] of Object.entries(tokens.typography.fontFamily)) {
    // Extract just the primary font name (first in the list)
    const fontName =
      typeof value === 'string' ? value.split(',')[0].replace(/'/g, '').trim() : value;
    lines.push(`        const val FONT_${key.toUpperCase()} = "${fontName}"`);
  }
  lines.push('');
  for (const [key, value] of Object.entries(tokens.typography.fontSize)) {
    const sizeKey = key.toUpperCase().replace('-', '');
    lines.push(`        const val SIZE_${sizeKey} = ${value}`);
  }
  lines.push('    }', '');

  // ── Motion
  lines.push('    // ── Motion ───────────────────────────────────────────────────────');
  lines.push('    object Motion {');
  for (const [key, value] of Object.entries(tokens.motion.duration)) {
    lines.push(`        const val ${key.toUpperCase()} = ${value}`);
  }
  lines.push('    }', '');

  // ── Layout
  lines.push('    // ── Layout ───────────────────────────────────────────────────────');
  lines.push('    object Layout {');
  lines.push(`        const val TOUCH_TARGET_MIN = ${tokens.layout.touchTargetMin}`);
  lines.push(`        const val MOBILE_GUTTER    = ${tokens.layout.mobileGutter}`);
  lines.push(`        const val MAX_WIDTH        = ${tokens.layout.maxContentWidth}`);
  lines.push('    }');

  lines.push('}', '');
  return lines.join('\n');
}

// ── 4. Swift ─────────────────────────────────────────────────────────
function generateSwift(): string {
  const lines: string[] = [
    '// Auto-generated from bytelyst.tokens.json — do not edit manually',
    'import SwiftUI',
    '',
    '// MARK: - MindLyst Design Tokens (from shared KMP MindLystTokens)',
    '// These values mirror MindLystTokens.kt exactly.',
    '',
    'struct MindLystColors {',
  ];

  // Dark colors
  lines.push('    // Dark');
  for (const [key, value] of Object.entries(tokens.color.semantic.dark)) {
    if (typeof value === 'string' && value.startsWith('#')) {
      lines.push(`    static let dark${capitalize(key)} = Color(hex: ${hexToUInt(value)})`);
    } else if (typeof value === 'string' && value.startsWith('rgba')) {
      // border/overlay → special handling
      if (key === 'borderDefault') {
        lines.push('    static let darkBorder  = Color.white.opacity(0.12)');
      }
    }
  }
  lines.push('');

  // Light colors
  lines.push('    // Light');
  for (const [key, value] of Object.entries(tokens.color.semantic.light)) {
    if (typeof value === 'string' && value.startsWith('#')) {
      if (value === '#FFFFFF') {
        lines.push(`    static let light${capitalize(key)} = Color.white`);
      } else {
        lines.push(`    static let light${capitalize(key)} = Color(hex: ${hexToUInt(value)})`);
      }
    }
  }
  lines.push('');

  // Brain gradients
  lines.push('    // Brain Gradients');
  for (const [name, grad] of Object.entries(tokens.color.brain) as [
    string,
    { from: string; to: string },
  ][]) {
    lines.push(
      `    static let brain${capitalize(name)} = Gradient(colors: [Color(hex: ${hexToUInt(grad.from)}), Color(hex: ${hexToUInt(grad.to)})])`
    );
  }
  lines.push('}', '');

  // Spacing
  lines.push('struct MindLystSpacing {');
  for (const [key, value] of Object.entries(tokens.spacing)) {
    const pad = key.length === 1 ? ' ' : '';
    lines.push(`    static let x${key}: ${pad}CGFloat = ${value}`);
  }
  lines.push('}', '');

  // Radius
  lines.push('struct MindLystRadius {');
  for (const [key, value] of Object.entries(tokens.radius)) {
    const pad = key.length < 4 ? ' '.repeat(4 - key.length) : '';
    lines.push(`    static let ${key}:${pad} CGFloat = ${value}`);
  }
  lines.push('}', '');

  // Motion (durations in seconds)
  lines.push('struct MindLystMotion {');
  for (const [key, value] of Object.entries(tokens.motion.duration)) {
    const seconds = (value as number) / 1000;
    const pad = key.length < 7 ? ' '.repeat(7 - key.length) : '';
    lines.push(`    static let ${key}:${pad} Double = ${seconds.toFixed(2)}`);
  }
  lines.push('}', '');

  // Color hex extension
  lines.push('// MARK: - Color Hex Extension');
  lines.push('');
  lines.push('extension Color {');
  lines.push('    init(hex: UInt, alpha: Double = 1.0) {');
  lines.push('        self.init(');
  lines.push('            .sRGB,');
  lines.push('            red:   Double((hex >> 16) & 0xFF) / 255.0,');
  lines.push('            green: Double((hex >> 8)  & 0xFF) / 255.0,');
  lines.push('            blue:  Double(hex & 0xFF) / 255.0,');
  lines.push('            opacity: alpha');
  lines.push('        )');
  lines.push('    }');
  lines.push('}', '');

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

// ── Write all ────────────────────────────────────────────────────────
writeFileSync(resolve(outDir, 'tokens.css'), generateCSS());
writeFileSync(resolve(outDir, 'tokens.ts'), generateTS());
writeFileSync(resolve(outDir, 'MindLystTokens.kt'), generateKotlin());
writeFileSync(resolve(outDir, 'MindLystTheme.swift'), generateSwift());

console.log('Generated 4 token files in generated/');
