// Copyright 2026 zmjknn
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
fn main {
  let args = @env.args()
  if args.length() <= 1 {
    // Default Demo Mode
    let demo = "## MoonMark\n一个纯 MoonBit 实现的解析器!"
    let parser = @parser.Parser::new(demo)
    let ast = parser.parse()
    let html = @html.Renderer::new().render(ast)
    println(html)
    return
  }

  let first = args[1]
  if first == "-h" || first == "--help" {
    print_help()
    return
  }

  if first == "--dir" || first == "-d" {
    if args.length() < 3 {
      println("Error: --dir requires an input directory path.")
      return
    }
    let input_dir = args[2]
    let mut output_dir = "dist"
    let mut i = 3
    while i < args.length() {
      if (args[i] == "-o" || args[i] == "--out-dir") && i + 1 < args.length() {
        output_dir = args[i + 1]
        i = i + 2
      } else {
        i = i + 1
      }
    }
    convert_directory(input_dir, output_dir)
    return
  }

  if first == "--batch" || first == "-b" {
    let files = []
    let mut output_dir = "dist"
    let mut i = 2
    while i < args.length() {
      if (args[i] == "-o" || args[i] == "--out-dir") && i + 1 < args.length() {
        output_dir = args[i + 1]
        i = i + 2
      } else {
        files.push(args[i])
        i = i + 1
      }
    }
    convert_files(files, output_dir)
    return
  }

  // Single file conversion mode
  let input_file = first
  let mut output_file : String? = None
  let mut i = 2
  while i < args.length() {
    if args[i] == "-o" && i + 1 < args.length() {
      output_file = Some(args[i + 1])
      i = i + 2
    } else {
      i = i + 1
    }
  }

  convert_single_file(input_file, output_file)
}

///|
fn convert_single_file(input_file : String, output_file : String?) -> Unit {
  try {
    let markdown = @fs.read_file_to_string(input_file)
    let parser = @parser.Parser::new(markdown)
    let ast = parser.parse()
    let html = @html.Renderer::new().render(ast)

    match output_file {
      Some(out_path) => {
        ensure_parent_dir(out_path)
        @fs.write_string_to_file(out_path, html)
        println("Successfully converted \{input_file} -> \{out_path}")
      }
      None => println(html)
    }
  } catch {
    _ => println("Error: Failed to read '\{input_file}' or write output.")
  }
}

///|
fn convert_files(files : Array[String], output_dir : String) -> Unit {
  if files.length() == 0 {
    println("Error: No files specified for batch conversion.")
    return
  }
  ensure_dir_exists(output_dir)
  for i = 0; i < files.length(); i = i + 1 {
    let file = files[i]
    let filename = get_filename(file)
    let out_path = @path.output_path(output_dir, "", filename)
    convert_single_file(file, Some(out_path))
  }
}

///|
fn convert_directory(input_dir : String, output_dir : String) -> Unit {
  convert_directory_recursive(input_dir, output_dir, "") catch {
    _ => println("Error: Failed to read directory '\{input_dir}'.")
  }
}

///|
fn convert_directory_recursive(
  input_dir : String,
  output_dir : String,
  relative_dir : String,
) -> Unit raise {
  let entries = @fs.read_dir(input_dir)
  for i = 0; i < entries.length(); i = i + 1 {
    let entry = entries[i]
    let input_path = input_dir + "/" + entry
    if @fs.is_dir(input_path) {
      let child_relative = if relative_dir.length() == 0 {
        entry
      } else {
        relative_dir + "/" + entry
      }
      convert_directory_recursive(input_path, output_dir, child_relative)
    } else if entry.has_suffix(".md") || entry.has_suffix(".markdown") {
      convert_single_file(
        input_path,
        Some(@path.output_path(output_dir, relative_dir, entry)),
      )
    }
  }
}

///|
fn ensure_dir_exists(dir_path : String) -> Unit {
  if !@fs.path_exists(dir_path) {
    @fs.create_dir(dir_path) catch {
      _ => ()
    }
  }
}

///|
fn ensure_parent_dir(file_path : String) -> Unit {
  let mut last_slash = -1
  for i = 0; i < file_path.length(); i = i + 1 {
    let ch = file_path[i]
    if ch == 47 || ch == 92 { // '/' or '\'
      last_slash = i
    }
  }
  if last_slash > 0 {
    let parent = file_path[0:last_slash].to_owned()
    ensure_dir_exists(parent)
  }
}

///|
fn get_filename(file_path : String) -> String {
  let mut last_slash = -1
  for i = 0; i < file_path.length(); i = i + 1 {
    let ch = file_path[i]
    if ch == 47 || ch == 92 {
      last_slash = i
    }
  }
  if last_slash >= 0 && last_slash + 1 < file_path.length() {
    file_path[last_slash + 1:file_path.length()].to_owned()
  } else {
    file_path
  }
}

///|
fn print_help() -> Unit {
  println("MoonMark CLI - High-Performance Markdown to HTML Converter")
  println("")
  println("Usage:")
  println("  1. Demo mode:")
  println("     moon run src/cli")
  println("  2. Single file conversion:")
  println("     moon run src/cli --  [-o ]")
  println("  3. Multi-file batch conversion:")
  println("     moon run src/cli -- --batch   ... [-o ]")
  println("  4. Directory batch conversion:")
  println("     moon run src/cli -- --dir  [-o ]")
  println("  5. Help:")
  println("     moon run src/cli -- -h | --help")
}