/// executions.mbt — executions 表 schema + CRUD。
///
/// 注意:moonbitlang/sqlite 的 SqlValue 仅支持 Text/Int,
/// 因此 cost 字段以 TEXT 存储(字符串化的浮点数),读回时 parse 为 Double。

///|
/// executions 表 CREATE TABLE SQL(使用 \n 避免跨行字面量)
pub fn executions_table_sql() -> String {
  "CREATE TABLE IF NOT EXISTS executions (\n    id TEXT PRIMARY KEY,\n    task_id TEXT NOT NULL DEFAULT '',\n    executor TEXT NOT NULL DEFAULT 'manual',\n    model TEXT NOT NULL DEFAULT '',\n    tokens_in INTEGER NOT NULL DEFAULT 0,\n    tokens_out INTEGER NOT NULL DEFAULT 0,\n    cost TEXT NOT NULL DEFAULT '0.0',\n    duration_ms INTEGER NOT NULL DEFAULT 0,\n    rate_limited INTEGER NOT NULL DEFAULT 0,\n    failure_reason TEXT NOT NULL DEFAULT '',\n    created_at TEXT NOT NULL DEFAULT ''\n)"
}

///|
/// 执行记录结构体
pub struct ExecutionRecord {
  id : String
  task_id : String
  executor : String
  model : String
  tokens_in : Int
  tokens_out : Int
  cost : Double
  duration_ms : Int
  rate_limited : Bool
  failure_reason : String
  created_at : String
}

///|
/// 初始化 executions 表
pub fn init_executions_table(db : @sqlite.Database) -> Bool {
  db.exec(executions_table_sql())
}

///|
/// 写入执行记录
pub fn insert_execution(
  db : @sqlite.Database,
  rec : ExecutionRecord,
) -> Result[Unit, String] {
  let sql = "INSERT INTO executions (id, task_id, executor, model, tokens_in, tokens_out, cost, duration_ms, rate_limited, failure_reason, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
  match db.prepare(sql) {
    None => Err("sqlite prepare 失败: insert_execution")
    Some(stmt) => {
      ignore(
        stmt.bind(1, @sqlite.SqlValue::Text(@encoding.encode(UTF8, rec.id))),
      )
      ignore(
        stmt.bind(
          2,
          @sqlite.SqlValue::Text(@encoding.encode(UTF8, rec.task_id)),
        ),
      )
      ignore(
        stmt.bind(
          3,
          @sqlite.SqlValue::Text(@encoding.encode(UTF8, rec.executor)),
        ),
      )
      ignore(
        stmt.bind(4, @sqlite.SqlValue::Text(@encoding.encode(UTF8, rec.model))),
      )
      ignore(stmt.bind(5, @sqlite.SqlValue::Int(rec.tokens_in)))
      ignore(stmt.bind(6, @sqlite.SqlValue::Int(rec.tokens_out)))
      // cost 以 TEXT 存储(SqlValue 不支持 Real)
      ignore(
        stmt.bind(
          7,
          @sqlite.SqlValue::Text(@encoding.encode(UTF8, rec.cost.to_string())),
        ),
      )
      ignore(stmt.bind(8, @sqlite.SqlValue::Int(rec.duration_ms)))
      ignore(
        stmt.bind(
          9,
          @sqlite.SqlValue::Int(if rec.rate_limited { 1 } else { 0 }),
        ),
      )
      ignore(
        stmt.bind(
          10,
          @sqlite.SqlValue::Text(@encoding.encode(UTF8, rec.failure_reason)),
        ),
      )
      ignore(
        stmt.bind(
          11,
          @sqlite.SqlValue::Text(@encoding.encode(UTF8, rec.created_at)),
        ),
      )
      let exec_ok = stmt.execute()
      stmt.finalize()
      if exec_ok {
        Ok(())
      } else {
        Err("sqlite 写入失败: \{rec.id}")
      }
    }
  }
}

///|
/// 列出全部执行记录(按 created_at DESC)
pub fn list_all_executions(db : @sqlite.Database) -> Array[ExecutionRecord] {
  let out : Array[ExecutionRecord] = []
  let sql = "SELECT id, task_id, executor, model, tokens_in, tokens_out, cost, duration_ms, rate_limited, failure_reason, created_at FROM executions ORDER BY created_at DESC"
  match db.prepare(sql) {
    None => out
    Some(stmt) => {
      while stmt.step() {
        out.push(row_to_execution(stmt))
      }
      stmt.finalize()
      out
    }
  }
}

///|
/// 聚合统计:总成本 / 总 token / 执行次数 / 按执行器分组
pub fn aggregate_stats(db : @sqlite.Database) -> Json {
  let records = list_all_executions(db)
  let mut total_cost : Double = 0.0
  let mut total_tokens_in : Int = 0
  let mut total_tokens_out : Int = 0
  let mut total_rate_limited : Int = 0
  let by_executor : Map[String, Json] = Map([])
  for rec in records {
    total_cost = total_cost + rec.cost
    total_tokens_in = total_tokens_in + rec.tokens_in
    total_tokens_out = total_tokens_out + rec.tokens_out
    if rec.rate_limited {
      total_rate_limited = total_rate_limited + 1
    }
    let key = rec.executor
    let existing = match by_executor.get(key) {
      Some(Object(m)) => m
      _ => Map([])
    }
    let count = match existing.get("count") {
      Some(Number(n, ..)) => n.to_int() + 1
      _ => 1
    }
    let cost_sum = match existing.get("cost") {
      Some(Number(n, ..)) => n + rec.cost
      _ => rec.cost
    }
    let new_m : Map[String, Json] = Map([
      ("count", Json::number(count.to_double())),
      ("cost", Json::number(cost_sum)),
    ])
    by_executor.set(key, Json::object(new_m))
  }
  Json::object({
    "total_records": Json::number(records.length().to_double()),
    "total_cost": Json::number(total_cost),
    "total_tokens_in": Json::number(total_tokens_in.to_double()),
    "total_tokens_out": Json::number(total_tokens_out.to_double()),
    "total_rate_limited": Json::number(total_rate_limited.to_double()),
    "by_executor": Json::object(by_executor),
  })
}

///|
fn row_to_execution(stmt : @sqlite.Statement) -> ExecutionRecord {
  let cost_str = str_from_stmt_text(stmt, 6)
  // 简单解析:取第一个 . 分隔的数字部分
  let cost = parse_simple_double(cost_str)
  ExecutionRecord::{
    id: str_from_stmt_text(stmt, 0),
    task_id: str_from_stmt_text(stmt, 1),
    executor: str_from_stmt_text(stmt, 2),
    model: str_from_stmt_text(stmt, 3),
    tokens_in: stmt.column_int(4),
    tokens_out: stmt.column_int(5),
    cost,
    duration_ms: stmt.column_int(7),
    rate_limited: stmt.column_int(8) != 0,
    failure_reason: str_from_stmt_text(stmt, 9),
    created_at: str_from_stmt_text(stmt, 10),
  }
}

///|
fn str_from_stmt_text(stmt : @sqlite.Statement, col : Int) -> String {
  str_from_bytes(stmt.column_text(col))
}

///|
/// 简单解析字符串为 Double(支持 "3.14" 格式)
fn parse_simple_double(s : String) -> Double {
  let mut integer_part : Int = 0
  let mut fractional_part : Int = 0
  let mut fractional_digits : Int = 0
  let mut found_dot : Bool = false
  let mut negative : Bool = false
  let mut i : Int = 0
  // 跳过前导空格
  while i < s.length() {
    let c = s[i]
    if c == ' ' {
      i = i + 1
    } else {
      break
    }
  }
  if i < s.length() && s[i] == '-' {
    negative = true
    i = i + 1
  }
  while i < s.length() {
    let c = s[i]
    if c >= '0' && c <= '9' {
      if found_dot {
        fractional_part = fractional_part * 10 + (c - '0').to_int()
        fractional_digits = fractional_digits + 1
      } else {
        integer_part = integer_part * 10 + (c - '0').to_int()
      }
      i = i + 1
    } else if c == '.' && !found_dot {
      found_dot = true
      i = i + 1
    } else {
      break
    }
  }
  let mut result : Double = integer_part.to_double()
  if fractional_digits > 0 {
    let mut divisor : Double = 1.0
    let mut j : Int = 0
    while j < fractional_digits {
      divisor = divisor * 10.0
      j = j + 1
    }
    result = result + fractional_part.to_double() / divisor
  }
  if negative {
    -result
  } else {
    result
  }
}