/// 声明式布局树(通用化的核心):
/// 模板只声明结构(vstack / hstack / 嵌套),几何完全由布局求解器决定。
/// 同一棵树放到 390 或 1280 宽的画布,坐标自动重排——
/// 模板不再是"排好的像素画",而是可适配任何设备的结构语义。
///
/// 这把"原型"从特定领域产物变成引擎能力:换设备、加内容、改密度,
/// 都不需要重新手排坐标。

///|
/// 布局树:节点本体 + 子树(Document.children 只存 id,构建期用 LT 携带子树)
pub(all) struct LT {
  node : Node
  kids : Array[LT]
}

///|
/// 垂直栈(默认占满父容器,子项沿主轴堆叠)
pub fn lt_v(
  id~ : String,
  gap? : Double = 0.0,
  pad? : Double = 0.0,
  kids? : Array[LT] = [],
) -> LT {
  {
    node: {
      ..Node::make(id, Frame),
      width: Fill,
      height: Fill,
      layout: Some({
        dir: Vertical,
        gap,
        justify: Start,
        padding: Padding::uniform(pad),
      }),
    },
    kids,
  }
}

///|
/// 水平栈(默认占满父容器)
pub fn lt_h(
  id~ : String,
  gap? : Double = 0.0,
  pad? : Double = 0.0,
  kids? : Array[LT] = [],
) -> LT {
  {
    node: {
      ..Node::make(id, Frame),
      width: Fill,
      height: Fill,
      layout: Some({
        dir: Horizontal,
        gap,
        justify: Start,
        padding: Padding::uniform(pad),
      }),
    },
    kids,
  }
}

///|
/// 文本(按排版令牌定字号;宽 Fill 高 Hug)。
/// 字号/文字色一律查 DesignTokens——结构式模板与组件目录、手机模板共用
/// 同一排版体系,不允许本文件自立字号表(双源漂移回归锚)。
pub fn lt_text(id~ : String, role~ : String, s~ : String) -> LT {
  let t = DesignTokens::default()
  let size = match t.resolve_font(role) {
    Some(v) => v
    None =>
      match t.resolve_font("body") {
        Some(v) => v
        None => 14.0
      }
  }
  // 字重无令牌角色,保留本地表(DesignTokens.typography 只有字号)
  let weight : String = match role {
    "h1" | "h2" => "700"
    "h3" | "h4" => "600"
    _ => "400"
  }
  {
    node: {
      ..Node::make(id, Text),
      width: Fill,
      height: Hug,
      style: {
        ..NodeStyle::default(),
        font_size: size,
        font_weight: weight,
        text_color: t.resolve_color("text_primary"),
      },
      text: s,
    },
    kids: [],
  }
}

///|
/// 通用盒(面板/背景/插图占位),宽高显式给定
pub fn lt_box(
  id~ : String,
  fill~ : String,
  w~ : Double,
  h~ : Double,
  radius? : Double = 12.0,
  shadow? : String = "none",
  stroke? : String = "none",
) -> LT {
  {
    node: {
      ..Node::make(id, Rect),
      width: Fixed(w),
      height: Fixed(h),
      style: {
        ..NodeStyle::default(),
        fill,
        corner_radius: radius,
        shadow,
        stroke,
      },
    },
    kids: [],
  }
}

///|
/// 弹性盒:吃满剩余空间(用作分隔/自适应留白)
pub fn lt_flex(id~ : String, fill? : String = "none") -> LT {
  {
    node: {
      ..Node::make(id, Rect),
      width: Fill,
      height: Fill,
      style: { ..NodeStyle::default(), fill, },
    },
    kids: [],
  }
}

///|
/// 按钮(主/次)——颜色查设计令牌,与组件目录 button 同源
pub fn lt_btn(
  id~ : String,
  label~ : String,
  variant? : String = "primary",
) -> LT {
  let t = DesignTokens::default()
  let (fill, tc) : (String, String) = if variant == "primary" {
    (t.resolve_color("primary"), t.resolve_color("on_primary"))
  } else {
    (t.resolve_color("surface_variant"), t.resolve_color("text_primary"))
  }
  {
    node: {
      ..Node::make(id, Rect),
      width: Fixed(if variant == "primary" { 152.0 } else { 140.0 }),
      height: Fixed(44.0),
      style: {
        ..NodeStyle::default(),
        fill,
        text_color: tc,
        corner_radius: 10.0,
        shadow: "e1",
      },
      text: label,
    },
    kids: [],
  }
}

///|
/// 输入框(占位文字用 text_hint,描边用 outline——与令牌体系同源)
pub fn lt_input(id~ : String, ph~ : String) -> LT {
  let t = DesignTokens::default()
  {
    node: {
      ..Node::make(id, Rect),
      width: Fill,
      height: Fixed(46.0),
      style: {
        ..NodeStyle::default(),
        fill: t.resolve_color("surface"),
        text_color: t.resolve_color("text_hint"),
        corner_radius: 10.0,
        stroke: t.resolve_color("outline"),
        shadow: "e1",
      },
      text: ph,
    },
    kids: [],
  }
}

///|
/// 圆形徽标
pub fn lt_dot(id~ : String, fill~ : String, d? : Double = 36.0) -> LT {
  {
    node: {
      ..Node::make(id, Rect),
      width: Fixed(d),
      height: Fixed(d),
      style: { ..NodeStyle::default(), fill, corner_radius: 999.0, },
    },
    kids: [],
  }
}

///|
/// 白卡(垂直栈 + 现代阴影 + 细边)——底色/描边查令牌
pub fn lt_card(
  id~ : String,
  gap? : Double = 8.0,
  pad? : Double = 20.0,
  kids? : Array[LT] = [],
) -> LT {
  let t = DesignTokens::default()
  {
    node: {
      ..Node::make(id, Frame),
      width: Fill,
      height: Fill,
      layout: Some({
        dir: Vertical,
        gap,
        justify: Start,
        padding: Padding::uniform(pad),
      }),
      style: {
        ..NodeStyle::default(),
        fill: t.resolve_color("surface"),
        corner_radius: 14.0,
        stroke: t.resolve_color("outline_variant"),
        shadow: "e2",
      },
    },
    kids: [],
  }
}

///|
/// 微调:主/副轴规格、cross 居中、文字颜色(声明处链式使用)
pub fn LT::w(self : LT, spec : SizeSpec) -> LT {
  { node: { ..self.node, width: spec, }, kids: self.kids, }
}

///|
pub fn LT::h(self : LT, spec : SizeSpec) -> LT {
  { node: { ..self.node, height: spec, }, kids: self.kids, }
}

///|
pub fn LT::cx(self : LT) -> LT {
  { node: { ..self.node, x: CenterInParent, }, kids: self.kids, }
}

///|
pub fn LT::color(self : LT, c : String) -> LT {
  {
    node: { ..self.node, style: { ..self.node.style, text_color: c, }, },
    kids: self.kids,
  }
}

///|
/// 把布局树构建为画板:递归插入,几何交给求解器
pub fn Project::build_artboard(
  self : Project,
  name~ : String,
  width~ : Double,
  height~ : Double,
  tree~ : LT,
) -> String {
  let ab = self.create_artboard(name~, width~, height~)
  match self.artboards.get(ab) {
    Some(art) => {
      // 树根铺满画布(root 是绝对容器)
      let rooted : LT = {
        node: { ..tree.node, x: Fixed(0.0), y: Fixed(0.0), },
        kids: tree.kids,
      }
      lt_insert(art.doc, "root", rooted)
      self.revision = self.revision + 1
    }
    None => ()
  }
  ab
}

///|
/// 递归插入:先挂本节点,再挂子树
fn lt_insert(doc : Document, parent : String, tree : LT) -> Unit {
  let n = tree.node
  let leaf = { ..n, children: [], }
  let _ = doc.insert_node(leaf, parent)
  for k in tree.kids.iter() {
    lt_insert(doc, n.id, k)
  }
}