// Tests for prompt_builder.mbt — Task 5.10 + 5.11
// Cross-target via moonbitlang/x/fs + moonbitlang/core/env.

///| Monotonic counter for unique tmp dirs across same-ms calls.
let _pb_tmp_counter : Array[Int] = [0]

fn _mkdtemp_pb() -> String {
  let tmp = (@env.get_env_var("TMPDIR")).unwrap_or("/tmp")
  _pb_tmp_counter[0] = _pb_tmp_counter[0] + 1
  let suffix = @env.now().to_string() + "-" + _pb_tmp_counter[0].to_string()
  let dir = tmp + "/mnemo-pb-" + suffix
  let _ = try? @fs.create_dir(dir)

  dir
}

fn _rmrf_pb(dir : String) -> Unit {
  let _ = try? @fs.remove_dir(dir)

}

fn _write_file_pb(path : String, content : String) -> Unit {
  let _ = try? @fs.write_string_to_file(path, content)

}

///| Recursive mkdir via @fs.create_dir (which is single-level).
fn _mkdir_p_pb(path : String) -> Unit {
  if @fs.path_exists(path) {
    return
  }
  let view = path.view()
  let mut last = -1
  let mut i = 0
  while i < view.length() {
    if view.get_char(i) is Some('/') {
      last = i
    }
    i = i + 1
  }
  if last > 0 {
    _mkdir_p_pb(view[0:last].to_string())
  }
  let _ = try? @fs.create_dir(path)

}

// ---------------------------------------------------------------------------
// Task 5.10: truncation + context file loader tests
// ---------------------------------------------------------------------------

test "pb_truncate: short content unchanged" {
  let short = "hello world"
  assert_eq(pb_truncate_content(short), short)
}

test "pb_truncate: long content head+tail+marker" {
  let long = String::make(25000, 'A')
  let out = pb_truncate_content(long)
  assert_eq(out.has_prefix("AAAA"), true)
  assert_eq(out.has_suffix("AAAA"), true)
  assert_eq(out.contains("chars truncated"), true)
}

test "pb_find_context_file: absent returns empty" {
  let dir = _mkdtemp_pb()
  let result = pb_find_context_file(dir)
  assert_eq(result, "")
  _rmrf_pb(dir)
}

test "pb_find_context_file: CLAUDE.md in cwd" {
  let dir = _mkdtemp_pb()
  _write_file_pb(dir + "/CLAUDE.md", "# rules")
  let result = pb_find_context_file(dir)
  assert_eq(result.contains("rules"), true)
  _rmrf_pb(dir)
}

// ---------------------------------------------------------------------------
// Task 5.11: SOUL loader + build_system_prompt tests
// ---------------------------------------------------------------------------

test "pb_load_soul_md: absent returns empty" {
  let dir = _mkdtemp_pb()
  let result = pb_load_soul_md(dir)
  assert_eq(result, "")
  _rmrf_pb(dir)
}

test "pb_load_soul_md: present returns content" {
  let dir = _mkdtemp_pb()
  _write_file_pb(dir + "/SOUL.md", "Be thorough.")
  let result = pb_load_soul_md(dir)
  assert_eq(result.contains("Be thorough"), true)
  _rmrf_pb(dir)
}

test "build_system_prompt: empty config has identity" {
  let hh = _mkdtemp_pb()
  let cwd = _mkdtemp_pb()
  let prompt = build_system_prompt({
    hermes_home: hh,
    cwd,
    platform: "",
    model: "",
    available_tools: [],
    disabled_skills: [],
  })
  assert_eq(prompt.contains("Ermes Agent"), true)
  assert_eq(prompt.contains("persistent memory"), true)
  _rmrf_pb(hh)
  _rmrf_pb(cwd)
}

test "build_system_prompt: SOUL.md included when present" {
  let hh = _mkdtemp_pb()
  let cwd = _mkdtemp_pb()
  _write_file_pb(hh + "/SOUL.md", "Be very precise.")
  let prompt = build_system_prompt({
    hermes_home: hh,
    cwd,
    platform: "",
    model: "",
    available_tools: [],
    disabled_skills: [],
  })
  assert_eq(prompt.contains("SOUL.md"), true)
  assert_eq(prompt.contains("Be very precise"), true)
  _rmrf_pb(hh)
  _rmrf_pb(cwd)
}

test "build_system_prompt: context file included" {
  let hh = _mkdtemp_pb()
  let cwd = _mkdtemp_pb()
  _write_file_pb(cwd + "/CLAUDE.md", "# rules\nUse ESM.")
  let prompt = build_system_prompt({
    hermes_home: hh,
    cwd,
    platform: "",
    model: "",
    available_tools: [],
    disabled_skills: [],
  })
  assert_eq(prompt.contains("Project Context"), true)
  assert_eq(prompt.contains("Use ESM"), true)
  _rmrf_pb(hh)
  _rmrf_pb(cwd)
}

test "build_system_prompt: assembly order identity before context" {
  let hh = _mkdtemp_pb()
  let cwd = _mkdtemp_pb()
  _write_file_pb(cwd + "/CLAUDE.md", "# project rules")
  let prompt = build_system_prompt({
    hermes_home: hh,
    cwd,
    platform: "",
    model: "",
    available_tools: [],
    disabled_skills: [],
  })
  // Identity must appear before Project Context in the output
  let idx_id = pb_index_of(prompt, "Ermes Agent")
  let idx_ctx = pb_index_of(prompt, "Project Context")
  assert_eq(idx_id < idx_ctx, true)
  _rmrf_pb(hh)
  _rmrf_pb(cwd)
}

// ---------------------------------------------------------------------------
// Model-specific guidance tests
// ---------------------------------------------------------------------------

test "build_system_prompt: OpenAI guidance for gpt-4o" {
  let hh = _mkdtemp_pb()
  let cwd = _mkdtemp_pb()
  let prompt = build_system_prompt({
    hermes_home: hh,
    cwd,
    platform: "",
    model: "gpt-4o",
    available_tools: [],
    disabled_skills: [],
  })
  assert_eq(prompt.contains("Execution discipline"), true)
  assert_eq(prompt.contains("tool_persistence"), true)
  _rmrf_pb(hh)
  _rmrf_pb(cwd)
}

test "build_system_prompt: Google guidance for gemini model" {
  let hh = _mkdtemp_pb()
  let cwd = _mkdtemp_pb()
  let prompt = build_system_prompt({
    hermes_home: hh,
    cwd,
    platform: "",
    model: "gemini-2.0-flash",
    available_tools: [],
    disabled_skills: [],
  })
  assert_eq(prompt.contains("Google model operational directives"), true)
  assert_eq(prompt.contains("Absolute paths"), true)
  _rmrf_pb(hh)
  _rmrf_pb(cwd)
}

test "build_system_prompt: no model-specific guidance for claude" {
  let hh = _mkdtemp_pb()
  let cwd = _mkdtemp_pb()
  let prompt = build_system_prompt({
    hermes_home: hh,
    cwd,
    platform: "",
    model: "claude-3-5-sonnet",
    available_tools: [],
    disabled_skills: [],
  })
  assert_eq(prompt.contains("Execution discipline"), false)
  assert_eq(prompt.contains("Google model operational directives"), false)
  _rmrf_pb(hh)
  _rmrf_pb(cwd)
}