(* SPDX-License-Identifier: MPL-2.0 *)
(* SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell *)

let module_name_of_path path =
  let base = Filename.basename path in
  let stem =
    try Filename.chop_extension base
    with Invalid_argument _ -> base
  in
  if String.length stem = 0 then "Module"
  else
    String.make 1 (Char.uppercase_ascii stem.[0])
    ^ String.sub stem 1 (String.length stem - 1)

let bullet_for_finding (f : Scanner.finding) =
  Printf.sprintf
    "//   - [%s] line %d: %s\n//       %s"
    (Scanner.kind_to_label f.kind)
    f.line
    (Scanner.kind_to_guidance f.kind)
    f.excerpt

let summarise_findings findings =
  let buf = Buffer.create 256 in
  if findings = [] then begin
    Buffer.add_string buf
      "// MIGRATE: scanner found no Phase-1 anti-patterns. A clean .res\n";
    Buffer.add_string buf
      "//          surface does not mean the port is mechanical —\n";
    Buffer.add_string buf
      "//          re-decomposition still applies (see PILOT.md upstream).";
    Buffer.contents buf
  end else begin
    Buffer.add_string buf
      (Printf.sprintf
         "// MIGRATE: %d migration consideration%s detected. Each entry below\n"
         (List.length findings)
         (if List.length findings = 1 then "" else "s"));
    Buffer.add_string buf
      "//          names the pattern, source line, and the AffineScript\n";
    Buffer.add_string buf
      "//          answer to consider before porting.";
    List.iter
      (fun f ->
        Buffer.add_char buf '\n';
        Buffer.add_string buf (bullet_for_finding f))
      findings;
    Buffer.contents buf
  end

let quote_block source =
  let lines = String.split_on_char '\n' source in
  let quoted = List.map (fun l -> "   " ^ l) lines in
  let buf = Buffer.create (String.length source + 64) in
  Buffer.add_string buf
    "/* ORIGINAL RESCRIPT — retained for reference; delete once port lands.\n";
  Buffer.add_string buf (String.concat "\n" quoted);
  Buffer.add_string buf "\n*/";
  Buffer.contents buf

let emit ~module_name ~source_path ~source ~findings =
  let buf = Buffer.create 4096 in
  let add s = Buffer.add_string buf s in
  add "// SPDX-License-Identifier: MPL-2.0\n";
  add "// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell\n";
  add "//\n";
  add (Printf.sprintf
         "// Generated by tools/res-to-affine from %s\n" source_path);
  add "// This is a Phase-1 SKELETON. It does NOT compile. Bodies are TODO.\n";
  add "// See tools/res-to-affine/README.md for the migration workflow.\n";
  add "//\n";
  add (summarise_findings findings);
  add "\n\n";
  add (Printf.sprintf "module %s\n\n" module_name);
  add "// TODO: re-decompose the original into focused AffineScript modules.\n";
  add "//       Effect-track each signature, replace mutable state with affine\n";
  add "//       records, and lift Result/Validation to fail-paths.\n";
  add "\n";
  add (quote_block source);
  add "\n";
  Buffer.contents buf

let emit_translation ~module_name ~source_path ~source ~findings ~translated =
  let buf = Buffer.create 4096 in
  let add s = Buffer.add_string buf s in
  add "// SPDX-License-Identifier: MPL-2.0\n";
  add "// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell\n";
  add "//\n";
  add (Printf.sprintf
         "// Generated by tools/res-to-affine from %s (--translate, Phase 3)\n"
         source_path);
  add "// PARTIAL PORT (Phase 3, slice 1): the fully-structural type\n";
  add "// declarations below are translated to compilable AffineScript; every\n";
  add "// other form is left as a TODO island — the markers and the quoted\n";
  add "// original record what still needs porting. Review before relying on it.\n";
  add "//\n";
  add (summarise_findings findings);
  add "\n\n";
  add (Printf.sprintf "module %s;\n\n" module_name);
  if translated = [] then begin
    add "// (no fully-structural type declarations were translatable here;\n";
    add "//  see the markers above and the original below.)\n"
  end else
    List.iter
      (fun (line, code) ->
        add (Printf.sprintf "// from .res line %d\n" line);
        add code;
        add "\n\n")
      translated;
  add "// TODO: port the remaining forms. The original ReScript is retained\n";
  add "//       below; re-decompose effectful / stateful / exception paths\n";
  add "//       per the markers before deleting it.\n";
  add "\n";
  add (quote_block source);
  add "\n";
  Buffer.contents buf

let emit_partial ~module_name ~source_path ~source ~findings ~translated =
  let buf = Buffer.create 4096 in
  let add s = Buffer.add_string buf s in
  add "// SPDX-License-Identifier: MPL-2.0\n";
  add "// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell\n";
  add "//\n";
  add (Printf.sprintf
         "// Generated by tools/res-to-affine from %s (--partial, #488)\n"
         source_path);
  add "// PARTIAL PORT (#488): module-top-level functions are rendered as `fn`\n";
  add "// skeletons with switch->match + best-effort expression translation.\n";
  add "// This output DELIBERATELY does NOT type-check — param/return types are\n";
  add "// `_` holes and un-translatable expressions/patterns are `() /* TODO */`\n";
  add "// / `_ /* TODO */`. Fill the holes (check against the quoted original)\n";
  add "// to finish the port.\n";
  add "//\n";
  add (summarise_findings findings);
  add "\n\n";
  add (Printf.sprintf "module %s;\n\n" module_name);
  if translated = [] then begin
    add "// (no module-top-level function bindings to port here; see the\n";
    add "//  markers above and the original below.)\n"
  end else
    List.iter
      (fun (line, code) ->
        add (Printf.sprintf "// from .res line %d\n" line);
        add code;
        add "\n\n")
      translated;
  add "// TODO: finish the port — fill the type holes and resolve the\n";
  add "//       `() /* TODO */` / `_ /* TODO */` islands per the markers.\n";
  add "\n";
  add (quote_block source);
  add "\n";
  Buffer.contents buf
