// el-style — The el-ui design system.
//
// Hierarchy:
//   1. Theme              — single source of truth, set at experience root
//   2. Semantic tokens    — Color::Primary, Spacing::Lg, Radius::Md, ...
//   3. StyleModifier      — fluent builder applied to any component
//   4. StyleSheet         — named rule sets, applied with .apply("card")
//
// Resolution flow:
//   component declares semantic token  →  theme resolves to RGBA / px  →
//   compiler emits CSS-in-JS for the browser target / NSColor for macOS / ...

// ── Color tokens ─────────────────────────────────────────────────────────────

let COLOR_PRIMARY:            String = "primary"
let COLOR_ON_PRIMARY:         String = "on_primary"
let COLOR_PRIMARY_CONTAINER:  String = "primary_container"
let COLOR_SECONDARY:          String = "secondary"
let COLOR_ON_SECONDARY:       String = "on_secondary"
let COLOR_BACKGROUND:         String = "background"
let COLOR_ON_BACKGROUND:      String = "on_background"
let COLOR_SURFACE:            String = "surface"
let COLOR_ON_SURFACE:         String = "on_surface"
let COLOR_SURFACE_VARIANT:    String = "surface_variant"
let COLOR_ERROR:              String = "error"
let COLOR_ON_ERROR:           String = "on_error"
let COLOR_OUTLINE:            String = "outline"
let COLOR_OUTLINE_VARIANT:    String = "outline_variant"

// A resolved RGBA quadruple, encoded as JSON for transport across the FFI.
type Rgba {
    r: Int   // 0-255
    g: Int   // 0-255
    b: Int   // 0-255
    a: Int   // 0-255 (we store alpha *256 to keep everything integer in El today)
}

fn rgba(r: Int, g: Int, b: Int, a: Int) -> Rgba {
    { "r": r, "g": g, "b": b, "a": a }
}

fn rgba_to_css(c: Rgba) -> String {
    "rgba(" + int_to_str(c.r) + "," + int_to_str(c.g) + "," + int_to_str(c.b)
        + "," + int_to_str(c.a) + ")"
}

fn parse_hex(hex: String) -> Rgba {
    let s: String = hex
    if str_starts_with(s, "#") { let s = str_slice(s, 1, str_len(s)) }
    let r: Int = hex_to_int(str_slice(s, 0, 2))
    let g: Int = hex_to_int(str_slice(s, 2, 4))
    let b: Int = hex_to_int(str_slice(s, 4, 6))
    let a: Int = 255
    if str_len(s) > 6 { let a = hex_to_int(str_slice(s, 6, 8)) }
    { "r": r, "g": g, "b": b, "a": a }
}

// ── ColorScheme: semantic token -> Rgba ──────────────────────────────────────

type ColorScheme {
    primary:           String   // hex
    on_primary:        String
    primary_container: String
    secondary:         String
    on_secondary:      String
    background:        String
    on_background:     String
    surface:           String
    on_surface:        String
    surface_variant:   String
    error:             String
    on_error:          String
    outline:           String
    outline_variant:   String
}

fn color_scheme_light() -> ColorScheme {
    { "primary": "#3b82f6", "on_primary": "#ffffff", "primary_container": "#dbeafe",
      "secondary": "#a855f7", "on_secondary": "#ffffff",
      "background": "#ffffff", "on_background": "#0f172a",
      "surface": "#f8fafc", "on_surface": "#0f172a", "surface_variant": "#e2e8f0",
      "error": "#dc2626", "on_error": "#ffffff",
      "outline": "#cbd5e1", "outline_variant": "#e2e8f0" }
}

fn color_scheme_dark() -> ColorScheme {
    { "primary": "#60a5fa", "on_primary": "#0f172a", "primary_container": "#1e3a8a",
      "secondary": "#c084fc", "on_secondary": "#0f172a",
      "background": "#0f172a", "on_background": "#f8fafc",
      "surface": "#1e293b", "on_surface": "#f8fafc", "surface_variant": "#334155",
      "error": "#f87171", "on_error": "#0f172a",
      "outline": "#475569", "outline_variant": "#334155" }
}

// Resolve a semantic color token to its hex value in the active scheme.
fn resolve_color(scheme: ColorScheme, token: String) -> String {
    if str_eq(token, "primary")           { return scheme.primary }
    if str_eq(token, "on_primary")        { return scheme.on_primary }
    if str_eq(token, "primary_container") { return scheme.primary_container }
    if str_eq(token, "secondary")         { return scheme.secondary }
    if str_eq(token, "on_secondary")      { return scheme.on_secondary }
    if str_eq(token, "background")        { return scheme.background }
    if str_eq(token, "on_background")     { return scheme.on_background }
    if str_eq(token, "surface")           { return scheme.surface }
    if str_eq(token, "on_surface")        { return scheme.on_surface }
    if str_eq(token, "surface_variant")   { return scheme.surface_variant }
    if str_eq(token, "error")             { return scheme.error }
    if str_eq(token, "on_error")          { return scheme.on_error }
    if str_eq(token, "outline")           { return scheme.outline }
    if str_eq(token, "outline_variant")   { return scheme.outline_variant }
    "#000000"
}

// ── Spacing scale ────────────────────────────────────────────────────────────

type SpacingScale {
    xs: Int
    sm: Int
    md: Int
    lg: Int
    xl: Int
    xxl: Int
}

fn spacing_default() -> SpacingScale {
    { "xs": 4, "sm": 8, "md": 16, "lg": 24, "xl": 32, "xxl": 48 }
}

fn resolve_spacing(s: SpacingScale, token: String) -> Int {
    if str_eq(token, "xs")  { return s.xs }
    if str_eq(token, "sm")  { return s.sm }
    if str_eq(token, "md")  { return s.md }
    if str_eq(token, "lg")  { return s.lg }
    if str_eq(token, "xl")  { return s.xl }
    if str_eq(token, "xxl") { return s.xxl }
    s.md
}

// ── Radius / shadow ──────────────────────────────────────────────────────────

type RadiusScale {
    none: Int
    sm:   Int
    md:   Int
    lg:   Int
    full: Int
}

fn radius_default() -> RadiusScale {
    { "none": 0, "sm": 4, "md": 8, "lg": 16, "full": 9999 }
}

type ShadowScale {
    sm: String   // CSS box-shadow string
    md: String
    lg: String
}

fn shadow_light() -> ShadowScale {
    { "sm": "0 1px 2px rgba(0,0,0,0.05)",
      "md": "0 4px 6px rgba(0,0,0,0.1)",
      "lg": "0 10px 15px rgba(0,0,0,0.1)" }
}

fn shadow_dark() -> ShadowScale {
    { "sm": "0 1px 2px rgba(0,0,0,0.4)",
      "md": "0 4px 6px rgba(0,0,0,0.5)",
      "lg": "0 10px 15px rgba(0,0,0,0.6)" }
}

// ── Typography ───────────────────────────────────────────────────────────────

type TextStyle {
    font_family: String
    font_size:   Int
    font_weight: Int   // 100..900
    line_height: Int   // px
    letter_spacing: Int  // hundredths of em
}

fn text_style_default() -> TextStyle {
    { "font_family": "system-ui, -apple-system, sans-serif",
      "font_size": 16, "font_weight": 400, "line_height": 24, "letter_spacing": 0 }
}

// ── Theme ────────────────────────────────────────────────────────────────────

let THEME_MODE_LIGHT:  String = "light"
let THEME_MODE_DARK:   String = "dark"
let THEME_MODE_SYSTEM: String = "system"

type Theme {
    mode:       String   // light | dark | system
    colors:     ColorScheme
    spacing:    SpacingScale
    radius:     RadiusScale
    shadows:    ShadowScale
    typography: TextStyle
}

fn theme_default_light() -> Theme {
    { "mode": "light", "colors": color_scheme_light(), "spacing": spacing_default(),
      "radius": radius_default(), "shadows": shadow_light(), "typography": text_style_default() }
}

fn theme_default_dark() -> Theme {
    { "mode": "dark", "colors": color_scheme_dark(), "spacing": spacing_default(),
      "radius": radius_default(), "shadows": shadow_dark(), "typography": text_style_default() }
}

// ── StyleSheet — named rule sets ─────────────────────────────────────────────
//
// A StyleSheet is a JSON object mapping selector -> declarations.
// Components apply by name: element.apply("card")

fn stylesheet_new() -> String {
    "{}"
}

fn stylesheet_define(sheet: String, name: String, css_decls: String) -> String {
    json_set(sheet, name, css_decls)
}

fn stylesheet_resolve(sheet: String, name: String) -> String {
    json_get(sheet, name)
}

// ── CSS emit ─────────────────────────────────────────────────────────────────
//
// Server-side render: theme → CSS custom properties block.
// Emit as a <style> tag or inject into an existing stylesheet string.

fn theme_to_css_vars(theme: Theme) -> String {
    let c: ColorScheme = theme.colors
    let s: SpacingScale = theme.spacing
    let r: RadiusScale  = theme.radius
    let sh: ShadowScale = theme.shadows
    let ty: TextStyle   = theme.typography
    "--el-primary:"            + c.primary            + ";"
    + "--el-on-primary:"       + c.on_primary         + ";"
    + "--el-primary-container:" + c.primary_container + ";"
    + "--el-secondary:"        + c.secondary          + ";"
    + "--el-on-secondary:"     + c.on_secondary       + ";"
    + "--el-bg:"               + c.background         + ";"
    + "--el-on-bg:"            + c.on_background      + ";"
    + "--el-surface:"          + c.surface            + ";"
    + "--el-on-surface:"       + c.on_surface         + ";"
    + "--el-surface-variant:"  + c.surface_variant    + ";"
    + "--el-error:"            + c.error              + ";"
    + "--el-outline:"          + c.outline            + ";"
    + "--el-outline-variant:"  + c.outline_variant    + ";"
    + "--el-space-xs:"  + int_to_str(s.xs)  + "px;"
    + "--el-space-sm:"  + int_to_str(s.sm)  + "px;"
    + "--el-space-md:"  + int_to_str(s.md)  + "px;"
    + "--el-space-lg:"  + int_to_str(s.lg)  + "px;"
    + "--el-space-xl:"  + int_to_str(s.xl)  + "px;"
    + "--el-space-xxl:" + int_to_str(s.xxl) + "px;"
    + "--el-radius-none:" + int_to_str(r.none) + "px;"
    + "--el-radius-sm:"   + int_to_str(r.sm)   + "px;"
    + "--el-radius-md:"   + int_to_str(r.md)   + "px;"
    + "--el-radius-lg:"   + int_to_str(r.lg)   + "px;"
    + "--el-radius-full:" + int_to_str(r.full) + "px;"
    + "--el-shadow-sm:"   + sh.sm + ";"
    + "--el-shadow-md:"   + sh.md + ";"
    + "--el-shadow-lg:"   + sh.lg + ";"
    + "--el-font-family:" + ty.font_family  + ";"
    + "--el-font-size:"   + int_to_str(ty.font_size)   + "px;"
    + "--el-font-weight:" + int_to_str(ty.font_weight) + ";"
    + "--el-line-height:" + int_to_str(ty.line_height) + "px"
}

fn theme_to_style_tag(theme: Theme) -> String {
    "<style>:root{" + theme_to_css_vars(theme) + "}</style>"
}

fn text_style_to_css(ts: TextStyle) -> String {
    "font-family:" + ts.font_family
    + ";font-size:" + int_to_str(ts.font_size) + "px"
    + ";font-weight:" + int_to_str(ts.font_weight)
    + ";line-height:" + int_to_str(ts.line_height) + "px"
}

// ── Entry — smoke test ───────────────────────────────────────────────────────

let theme: Theme = theme_default_light()
println("[el-style] light primary = " + theme.colors.primary)
println("[el-style] css vars = " + theme_to_css_vars(theme))
