///|
/// 开箱即用的 CSS 编译门面
///
/// 注册全部内置后端引擎,提供一个无需手动拼装的 `compile` 入口。
///
/// # Example
/// ```mbt check
/// test {
///   inspect(compile("body { color: red; }"), content="body { color: red; }")
/// }
/// ```
pub fn compile(source : String) -> String raise @core.CompileError {
  default().compile(source)
}

///|
/// 以显式格式编译
pub fn compile_with_format(
  source : String,
  fmt : @core.Format,
) -> String raise @core.CompileError {
  default().compile_with_format(source, fmt)
}

///|
/// 依据输入形态编译
pub fn compile_input(input : @core.Input) -> String raise @core.CompileError {
  default().compile_input(input)
}

///|
/// 编译文件(读取函数由调用方注入)
pub fn compile_file(
  path : String,
  read : (String) -> String raise @core.CompileError,
) -> String raise @core.CompileError {
  default().compile_file(path, read)
}

///|
/// 以显式 SCSS 格式编译
pub fn compile_scss(source : String) -> String raise @core.CompileError {
  default().compile_with_format(source, @core.Scss)
}

///|
/// 以显式 SCSS 格式编译,并注入一组预置全局变量
///
/// 用法:源码里可能有未定义的 `$c`,这里传入 `{c: "10px"}`,
/// 等价于在源码前先写上 `$c: 10px;`(预置全局变量)。
/// 源码中若再次定义同名变量,会按 SCSS 的覆盖规则生效。
/// 例如 `compile_scss_with_vars("body { color: $c; }", {c:"red"})` → `body { color: red; }`
pub fn compile_scss_with_vars(
  source : String,
  vars : Map[String, String],
) -> String raise @core.CompileError {
  compile_prefixed_vars(source, vars, prefix="$", compile_scss)
}

///|
/// 以显式 LESS 格式编译,并注入一组预置全局变量
pub fn compile_less_with_vars(
  source : String,
  vars : Map[String, String],
) -> String raise @core.CompileError {
  compile_prefixed_vars(source, vars, prefix="@", compile_less)
}

///| 编译多个源码片段并拼接结果

///|

///|
/// 这是不需要文件读取器的轻量入口;涉及 `@import` 或文件路径时使用 `compile_many`。
pub fn compile_sources(
  sources : Array[String],
) -> String raise @core.CompileError {
  sources.map(source => compile(source)).join("\n")
}

///|
fn compile_prefixed_vars(
  source : String,
  vars : Map[String, String],
  prefix~ : String,
  compile : (String) -> String raise @core.CompileError,
) -> String raise @core.CompileError {
  let sb = StringBuilder()
  vars.each(fn(k, v) {
    sb.write_string(prefix)
    sb.write_string(k)
    sb.write_string(": ")
    sb.write_string(v)
    sb.write_string(";\n")
  })
  compile(sb.to_string() + source)
}

///|
/// 保守压缩 CSS:去块注释、多余空白与换行;**字符串值内的内容原样保留**
///
/// 用于生成 `.min.css`。只做安全替换(空白/换行/符号前空格/注释),
/// 不删可省略的末尾分号,也不做选择器合并等激进优化。
pub fn minify_css(css : String) -> String {
  let sb = StringBuilder()
  let n = css.length()
  let mut i = 0
  let mut need_space = false
  let mut has_written = false
  let mut last_was_punct = false
  while i < n {
    let c : UInt16 = css[i]
    // 空白折叠:只在“上一个是非符号 token”时补一个空格(符号两侧的空白都去)
    if c == 0x20 || c == 0x09 || c == 0x0A || c == 0x0D {
      need_space = has_written && last_was_punct == false
      i += 1
      continue
    }
    // 跳过块注释 /* ... */(保留注释前的空白状态,避免 a /*x*/ b 压成 ab)
    if c == 0x2F && i + 1 < n && css[i + 1] == 0x2A {
      let mut j = i + 2
      while j + 1 < n && (css[j] != 0x2A || css[j + 1] != 0x2F) {
        j += 1
      }
      i = if j + 1 < n { j + 2 } else { n }
      continue
    }
    // 字符串原样复制(含内部空白),防止损坏值
    if c == 0x22 || c == 0x27 {
      let q = c
      write_cs(sb, q)
      i += 1
      while i < n {
        let ch = css[i]
        write_cs(sb, ch)
        i += 1
        if ch == 0x5C && i < n {
          write_cs(sb, css[i])
          i += 1
          continue
        }
        if ch == q {
          break
        }
      }
      need_space = false
      has_written = true
      last_was_punct = false
      continue
    }
    if is_css_punct(c) {
      write_cs(sb, c)
      last_was_punct = true
    } else {
      if need_space {
        sb.write_string(" ")
      }
      write_cs(sb, c)
      last_was_punct = false
    }
    need_space = false
    has_written = true
    i += 1
  }
  sb.to_string()
}

///|
/// CSS 里符号前(及相邻)可安全去空格的字符
fn is_css_punct(c : UInt16) -> Bool {
  c == 0x7B || c == 0x7D || c == 0x3B || c == 0x3A || c == 0x2C || c == 0x3E
}

///|
/// 把 UTF-16 code unit 写入 StringBuilder
fn write_cs(sb : StringBuilder, c : UInt16) -> Unit {
  sb.write_char(Int::unsafe_to_char(c.to_int()))
}

///|
/// 以显式 LESS 格式编译
pub fn compile_less(source : String) -> String raise @core.CompileError {
  default().compile_with_format(source, @core.Less)
}

///|
/// 以显式 CSS 格式编译
pub fn compile_css(source : String) -> String raise @core.CompileError {
  default().compile_with_format(source, @core.Css)
}

///|
/// 编译多个输入(文件/字符串混用),带 @import 内联
pub fn compile_many(
  inputs : Array[@core.Input],
  read : (String) -> String raise @core.CompileError,
) -> String raise @core.CompileError {
  default().compile_many(inputs, read)
}

///|
/// 内置引擎组成的默认门面
fn default() -> @core.Compiler {
  @core.Compiler::new([
    @css.css_engine(),
    @scss.scss_engine(),
    @less.less_engine(),
  ])
}