// jeeflow-persist —— 移植自 rust jeeflow-persist/src/lib.rs
// DynamicTableWriter + PersistPostInterceptor(ARCHIVE/SYNC,spec/09)+ 元数据 + 表名安全。

///|
/// 字段元数据(动态表列)
pub(all) struct FieldMeta {
  mut column_name : String
  mut column_type : String
  mut display_name : String
  mut nullable : Bool
  mut default_value : String?
  mut permission : Int // 1 只读 / 2 可编辑 / 3 隐藏
}

///|
pub fn FieldMeta::make(column_name : String, column_type : String, display_name : String) -> FieldMeta {
  {
    column_name,
    column_type,
    display_name,
    nullable: true,
    default_value: None,
    permission: 2,
  }
}

///|
pub fn FieldMeta::is_editable(self : FieldMeta) -> Bool {
  self.permission == 2
}

///|
pub fn FieldMeta::is_visible(self : FieldMeta) -> Bool {
  self.permission != 3
}

///|
pub(all) struct TableMeta {
  mut table_name : String
  mut display_name : String
  mut fields : Array[FieldMeta]
}

///|
pub fn TableMeta::make(table_name : String, display_name : String) -> TableMeta {
  { table_name, display_name, fields: [] }
}

///|
pub fn TableMeta::add_field(self : TableMeta, field : FieldMeta) -> Unit {
  self.fields.push(field)
}

///|
pub fn TableMeta::get_field(self : TableMeta, column_name : String) -> FieldMeta? {
  let mut found : FieldMeta? = None
  for f in self.fields {
    if f.column_name == column_name {
      found = Some(f)
    }
  }
  found
}

///|
/// IDynamicMetaProvider 内存实现
pub(all) struct InMemoryMetaProvider {
  tables : Map[String, TableMeta]
}

///|
pub fn InMemoryMetaProvider::new() -> InMemoryMetaProvider {
  { tables: Map::new() }
}

///|
pub fn InMemoryMetaProvider::register(self : InMemoryMetaProvider, meta : TableMeta) -> Unit {
  self.tables[meta.table_name] = meta
}

///|
pub fn InMemoryMetaProvider::get_table_meta(
  self : InMemoryMetaProvider,
  table_name : String
) -> TableMeta? raise @error.JeeflowError {
  self.tables.get(table_name)
}

///|
pub fn InMemoryMetaProvider::list_table_names(self : InMemoryMetaProvider) -> Array[String] {
  let out : Array[String] = []
  for k, _ in self.tables {
    out.push(k)
  }
  out
}

///|
let reserved_prefixes : Array[String] = [
  "sys_", "wf_", "mysql.", "information_schema.", "pg_", "sqlite_",
]

///|
/// 动态表名安全检查:仅字母数字下划线 + 保留前缀拒绝
pub fn is_table_name_safe(name : String) -> Bool {
  if name.is_empty() {
    return false
  }
  for ch in name {
    let c = ch.to_int()
    let alnum = c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122
    if !(alnum || ch == '_') {
      return false
    }
  }
  let lower = name.to_lower()
  for prefix in reserved_prefixes {
    if lower.starts_with(prefix) {
      return false
    }
  }
  true
}

///|
/// 持久化模式
pub enum PersistMode {
  Archive
  Sync
} derive(Eq, Show)

///|
pub fn PersistMode::from_str(s : String) -> PersistMode? {
  match s.to_upper() {
    "ARCHIVE" => Some(Archive)
    "SYNC" => Some(Sync)
    _ => None
  }
}

///|
/// DynamicTableWriter trait(MoonBit:大接口 trait 形态)
pub(open) trait DynamicTableWriter {
  fn insert(Self, String, Map[String, Json]) -> Int64 raise @error.JeeflowError
  fn update(Self, String, Int64, Map[String, Json]) -> Unit raise @error.JeeflowError
  fn exists(Self, String, Int64) -> Bool raise @error.JeeflowError
  fn exists_by_key(Self, String, String, Int64) -> Bool raise @error.JeeflowError
  fn update_by_key(Self, String, Map[String, Json], String, Int64) -> Unit raise @error.JeeflowError
  // 探测实际存在的列(状态字段 {节点ID}_{状态码}/{节点ID} 过滤);缺省全保留
  fn columns(Self, String, Array[String]) -> Array[String] raise @error.JeeflowError
}

///|
/// 系统字段填充(时间走 Clock 注入口,D-M0-3)
pub fn fill_system_fields(
  data : Map[String, Json],
  operator : String,
  is_insert : Bool
) -> Unit {
  let now = @model.current_time_str()
  if is_insert {
    data["create_time"] = @json.string_of(now)
    data["create_user"] = @json.string_of(operator)
  }
  data["update_time"] = @json.string_of(now)
  data["update_user"] = @json.string_of(operator)
}