// parse.mbt - Markdown parsing with async file I/O

///|
/// Parse a markdown file and generate manifest
pub async fn parse_file(input_path : String, output_dir : String) -> Bool {
  println("Parsing file: \{input_path}")

  // Read the input file
  let content = read_file(input_path)

  // Split into pages (simplified - split by ---)
  let pages = split_pages_simple(content)
  println("   Found \{pages.length()} pages")

  // Create output directories
  create_dir_all(output_dir)
  create_dir_all(audio_dir(output_dir))

  // Process each page
  let slides : Array[SlideInfo] = []
  let videos : Array[VideoSegment] = []
  for i, page in pages {
    let slide_id = pad_slide_id(i + 1)

    // Extract video markers and their SSMLs (if any)
    let (page_videos, page_without_videos) = extract_videos(page)

    // Extract slide SSML from the page (without video content)
    let ssml = extract_ssml_simple(page_without_videos)
    let has_audio = !ssml.is_empty()
    let ssml_hash = if has_audio { hash_content(ssml) } else { "" }
    slides.push({ id: slide_id, ssml_hash, has_audio, })

    // Save slide SSML if present
    if has_audio {
      let ssml_file = slide_ssml_path(output_dir, slide_id)
      write_file(ssml_file, ssml)
      println("   [+] slide-\{slide_id}: Saved SSML (\{ssml.length()} chars)")
    } else {
      println("   [ ] slide-\{slide_id}: No audio")
    }

    // Handle video insertions for this slide
    for video_idx, video_info in page_videos {
      let has_video_audio = !video_info.ssml.is_empty()
      let video_ssml_hash = if has_video_audio {
        hash_content(video_info.ssml)
      } else {
        ""
      }
      videos.push({
        after_slide: slide_id,
        video_path: video_info.path,
        ssml_hash: video_ssml_hash,
        has_audio: has_video_audio,
      })

      // Save video SSML if present (always use indexed naming)
      if has_video_audio {
        let video_ssml_file = video_ssml_path_indexed(
          output_dir,
          slide_id,
          video_idx + 1,
        )
        write_file(video_ssml_file, video_info.ssml)
        println(
          "   [VIDEO] Insert video after slide-\{slide_id}: \{video_info.path} (with audio, \{video_info.ssml.length()} chars)",
        )
      } else {
        println(
          "   [VIDEO] Insert video after slide-\{slide_id}: \{video_info.path}",
        )
      }
    }
  }

  // Create manifest
  let manifest : Manifest = { slides, videos, }

  // Save manifest as JSON
  let manifest_file = manifest_path(output_dir)
  let manifest_json = Json::stringify(manifest.to_json())
  write_file(manifest_file, manifest_json)
  println("   [+] Saved manifest.json")
  println("\nParsing complete!")
  println("   Output: \{output_dir}")
  true
}

///|
/// Simple page splitting by --- delimiter and headingDivider
fn split_pages_simple(content : String) -> Array[String] {
  let result : Array[String] = []
  let lines : Array[String] = []
  for view in content.split("\n") {
    lines.push(view.to_owned())
  }

  // Check if headingDivider: 1 is in frontmatter
  let mut has_heading_divider = false
  let mut in_frontmatter = true
  let mut frontmatter_count = 0
  for line in lines {
    if line.trim(char_set=" \t") == "---" {
      frontmatter_count += 1
      if frontmatter_count == 2 {
        break
      }
    }
    if frontmatter_count == 1 && line.contains("headingDivider: 1") {
      has_heading_divider = true
    }
  }
  let current_page : Array[String] = []
  in_frontmatter = true
  frontmatter_count = 0
  for line in lines {
    // Handle frontmatter - skip it entirely when using headingDivider
    if line.trim(char_set=" \t") == "---" {
      if in_frontmatter {
        frontmatter_count += 1
        if frontmatter_count == 2 {
          in_frontmatter = false
        }
        // Don't add frontmatter lines when using headingDivider
        if !has_heading_divider {
          current_page.push(line)
        }
        continue
      } else {
        // Page separator (only used when NOT using headingDivider)
        if current_page.length() > 0 {
          result.push(current_page.join("\n"))
          current_page.clear()
        }
        continue
      }
    }

    // Skip frontmatter content when using headingDivider
    if in_frontmatter && has_heading_divider {
      continue
    }

    // If headingDivider: 1, split on "# " headings
    if !in_frontmatter && has_heading_divider && line.has_prefix("# ") {
      // Only save previous page if it has substantial content (not just whitespace)
      if current_page.length() > 0 {
        let has_content = current_page
          .iter()
          .any(fn(l) { !l.trim(char_set=" \t\n").is_empty() })
        if has_content {
          result.push(current_page.join("\n"))
        }
        current_page.clear()
      }
    }
    current_page.push(line)
  }

  // Add last page
  if current_page.length() > 0 {
    result.push(current_page.join("\n"))
  }
  result
}

///|
/// Extract SSML from page content
fn extract_ssml_simple(page : String) -> String {
  let mut result = ""
  let mut in_ssml = false
  let lines : Array[String] = []
  for view in page.split("\n") {
    lines.push(view.to_owned())
  }
  for line in lines {
    let trimmed = line.trim(char_set=" \t")
    if trimmed == "" && in_ssml {
      in_ssml = false
      continue
    }
    if in_ssml {
      result = result + line + "\n"
    }
  }
  result.trim(char_set=" \t\n").to_owned()
}

///|
/// Video info extracted from a page
priv struct VideoInfo {
  path : String
  ssml : String
}

///|
/// Extract video markers and optional SSMLs from page
/// Returns (videos, page_without_videos)
fn extract_videos(page : String) -> (Array[VideoInfo], String) {
  // Look for:
  // -  (no SSML)
  // -  (with SSML)
  let lines : Array[String] = []
  for view in page.split("\n") {
    lines.push(view.to_owned())
  }
  let videos : Array[VideoInfo] = []
  let mut current_video_path = ""
  let mut current_video_ssml = ""
  let mut in_video_ssml = false
  let result_lines : Array[String] = []
  let mut i = 0
  while i < lines.length() {
    let line = lines[i]
    let trimmed = line.trim(char_set=" \t")

    // Check for video marker with SSML: 
    if trimmed.has_prefix("") {
      // Extract video path: 
      let start = "".length()
      guard start <= end else {
        i += 1
        continue
      }
      let path_str = trimmed[start:end].to_owned()
      let video_path = path_str.trim(char_set=" \t").to_owned()
      videos.push({ path: video_path, ssml: "", })
      i += 1
      continue
    }

    // If in video SSML block, collect until -->
    if in_video_ssml {
      if trimmed == "-->" {
        // End of SSML block - save video
        videos.push({
          path: current_video_path,
          ssml: current_video_ssml.trim(char_set=" \t\n").to_owned(),
        })
        current_video_path = ""
        current_video_ssml = ""
        in_video_ssml = false
        i += 1
        continue
      }
      current_video_ssml = current_video_ssml + line + "\n"
      i += 1
      continue
    }

    // Keep lines that aren't video-related
    result_lines.push(line)
    i += 1
  }
  let page_without_videos = result_lines.join("\n")
  (videos, page_without_videos)
}

///|
/// Get course name from input file path
pub fn get_course_name_from_path(input_file : String) -> String {
  // Get the filename without path
  let file_name = basename(input_file)

  // Remove .mbt.md or .md extension
  let mut base_name = file_name
  if base_name.has_suffix(".mbt.md") {
    let len = base_name.length()
    base_name = base_name[0:len - 7].to_owned()
  } else if base_name.has_suffix(".md") {
    let len = base_name.length()
    base_name = base_name[0:len - 3].to_owned()
  }

  // Use the base filename as the target directory name
  // Examples:
  //   lec7-1.mbt.md -> target/lec7-1/
  //   lec7-2.mbt.md -> target/lec7-2/
  //   slides.md -> target/slides/
  base_name
}

///|
extend Manifest with ToJson::{to_json}