//! Docs subcommand handlers
//!
//! Handles: cr docs search, read, read-lines, list

use calcit::cli_args::{DocsCommand, DocsSubcommand};
use colored::Colorize;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::Once;
use std::time::{Duration, SystemTime};

use calcit::ProgramEntries;
use calcit::calcit::LocatedWarning;
use calcit::call_stack::CallStackList;
use calcit::program;
use calcit::runner;
use calcit::snapshot;
use calcit::util;

use super::markdown_read::{RenderMarkdownOptions, render_markdown_sections};

#[derive(Debug, Clone)]
pub struct GuideDoc {
  filename: String,
  path: String,
  content: String,
}

struct ReadRenderOptions<'a> {
  display_title: &'a str,
  display_path: &'a str,
  command_hint: &'a str,
  no_match_error: &'a str,
  content: &'a str,
  heading_queries: &'a [String],
  include_subheadings: bool,
  full: bool,
  with_lines: bool,
}

pub fn handle_docs_command(cmd: &DocsCommand) -> Result<(), String> {
  match &cmd.subcommand {
    DocsSubcommand::Search(opts) => handle_search(&opts.keyword, opts.context, opts.filename.as_deref()),
    DocsSubcommand::Read(opts) => handle_read(&opts.filename, &opts.headings, !opts.no_subheadings, opts.full, opts.with_lines),
    DocsSubcommand::Agents(opts) => handle_agents(&opts.headings, !opts.no_subheadings, opts.full, opts.with_lines, opts.refresh),
    DocsSubcommand::ReadLines(opts) => handle_read_lines(&opts.filename, opts.start, opts.lines),
    DocsSubcommand::List(_) => handle_list(),
    DocsSubcommand::CheckMd(opts) => handle_check_md(&opts.file, &opts.entry, &opts.dep),
  }
}

const AGENTS_DOC_URL: &str = "https://repo.calcit-lang.org/calcit/docs/CalcitAgent.md";

fn get_agents_cache_path() -> Result<PathBuf, String> {
  let home_dir = std::env::var("HOME").map_err(|_| "Unable to get HOME environment variable".to_string())?;
  Ok(Path::new(&home_dir).join(".config/calcit/Agents.md"))
}

fn needs_agents_refresh(cache_path: &Path) -> bool {
  if !cache_path.exists() {
    return true;
  }

  let metadata = match fs::metadata(cache_path) {
    Ok(m) => m,
    Err(_) => return true,
  };

  let modified = match metadata.modified() {
    Ok(m) => m,
    Err(_) => return true,
  };

  let now = SystemTime::now();
  match now.duration_since(modified) {
    Ok(age) => age > Duration::from_secs(24 * 60 * 60),
    Err(_) => true,
  }
}

fn download_agents_doc() -> Result<String, String> {
  let response = ureq::get(AGENTS_DOC_URL)
    .call()
    .map_err(|e| format!("Failed to download Agents.md: {e}"))?;

  response
    .into_body()
    .read_to_string()
    .map_err(|e| format!("Failed to read Agents.md response: {e}"))
}

fn ensure_agents_cache(force_refresh: bool) -> Result<(PathBuf, bool), String> {
  let cache_path = get_agents_cache_path()?;
  let should_refresh = force_refresh || needs_agents_refresh(&cache_path);

  if should_refresh {
    let content = download_agents_doc()?;
    if let Some(parent) = cache_path.parent() {
      fs::create_dir_all(parent).map_err(|e| format!("Failed to create cache directory {parent:?}: {e}"))?;
    }
    fs::write(&cache_path, content).map_err(|e| format!("Failed to write Agents cache {cache_path:?}: {e}"))?;
  }

  Ok((cache_path, should_refresh))
}

fn handle_read_content(options: ReadRenderOptions<'_>) -> Result<(), String> {
  let command_prefix = format!("cr docs {}", options.command_hint);

  println!("{} ({})", options.display_title.cyan().bold(), options.display_path.dimmed());
  println!("{}", "=".repeat(60).dimmed());

  render_markdown_sections(
    options.content,
    options.heading_queries,
    RenderMarkdownOptions {
      include_subheadings: options.include_subheadings,
      full: options.full,
      with_lines: options.with_lines,
      command_prefix: &command_prefix,
      with_file_option: false,
      no_headings_message: "No Markdown headings found in this document.",
      print_full_when_no_headings: false,
      no_match_error: options.no_match_error,
    },
  )
}

fn find_doc_by_filename<'a>(guide_docs: &'a HashMap<String, GuideDoc>, filename: &str) -> Result<&'a GuideDoc, String> {
  guide_docs
    .values()
    .find(|d| d.filename == filename || d.filename.contains(filename))
    .ok_or_else(|| format!("Document '{filename}' not found. Use 'cr docs list' to see available documents."))
}

fn get_guidebook_dir() -> Result<std::path::PathBuf, String> {
  let home_dir = std::env::var("HOME").map_err(|_| "Unable to get HOME environment variable")?;
  let docs_dir = Path::new(&home_dir).join(".config/calcit/guidebook-repo/docs");

  if !docs_dir.exists() {
    return Err(format!(
      "Guidebook documentation directory not found: {docs_dir:?}\n\n\
       To set up guidebook documentation, please run:\n\
       git clone https://github.com/calcit-lang/guidebook-repo.git ~/.config/calcit/guidebook-repo"
    ));
  }

  Ok(docs_dir)
}

fn load_guidebook_docs() -> Result<HashMap<String, GuideDoc>, String> {
  let docs_dir = get_guidebook_dir()?;
  let mut guide_docs = HashMap::new();

  fn visit_dir(dir: &Path, base_dir: &Path, docs: &mut HashMap<String, GuideDoc>) -> Result<(), String> {
    for entry in fs::read_dir(dir).map_err(|e| format!("Failed to read directory: {e}"))? {
      let entry = entry.map_err(|e| format!("Failed to read directory entry: {e}"))?;
      let path = entry.path();

      if path.is_dir() {
        visit_dir(&path, base_dir, docs)?;
      } else if path.extension().and_then(|s| s.to_str()) == Some("md") {
        let content = fs::read_to_string(&path).map_err(|e| format!("Failed to read file {path:?}: {e}"))?;
        let relative_path = path.strip_prefix(base_dir).map_err(|_| "Unable to get relative path")?;
        let filename = path.file_name().and_then(|s| s.to_str()).unwrap_or("unknown").to_string();

        docs.insert(
          filename.clone(),
          GuideDoc {
            filename,
            path: relative_path.to_string_lossy().to_string(),
            content,
          },
        );
      }
    }
    Ok(())
  }

  visit_dir(&docs_dir, &docs_dir, &mut guide_docs)?;
  Ok(guide_docs)
}

fn handle_search(keyword: &str, context_lines: usize, filename_filter: Option<&str>) -> Result<(), String> {
  let guide_docs = load_guidebook_docs()?;

  let mut found_any = false;

  for doc in guide_docs.values() {
    // Skip SUMMARY files
    if doc.filename.to_uppercase().contains("SUMMARY") {
      continue;
    }

    // Apply filename filter if provided
    if let Some(filter) = filename_filter {
      if !doc.filename.contains(filter) {
        continue;
      }
    }

    let lines: Vec<&str> = doc.content.lines().collect();
    let mut matching_ranges: Vec<(usize, usize)> = Vec::new();

    // Find all matching lines
    for (line_num, line) in lines.iter().enumerate() {
      if line.contains(keyword) {
        let start = line_num.saturating_sub(context_lines);
        let end = (line_num + context_lines + 1).min(lines.len());
        matching_ranges.push((start, end));
      }
    }

    if matching_ranges.is_empty() {
      continue;
    }

    found_any = true;

    // Merge overlapping ranges
    matching_ranges.sort_by_key(|r| r.0);
    let mut merged_ranges: Vec<(usize, usize)> = Vec::new();
    for (start, end) in matching_ranges {
      if let Some(last) = merged_ranges.last_mut() {
        if start <= last.1 {
          last.1 = last.1.max(end);
          continue;
        }
      }
      merged_ranges.push((start, end));
    }

    // Display matches
    println!("{} ({})", doc.filename.cyan().bold(), doc.path.dimmed());
    println!("{}", "-".repeat(60).dimmed());

    for (start, end) in merged_ranges {
      for (idx, line) in lines[start..end].iter().enumerate() {
        let line_num = start + idx + 1;
        if line.contains(keyword) {
          println!("{} {}", format!("{line_num:4}:").yellow(), line);
        } else {
          println!("{} {}", format!("{line_num:4}:").dimmed(), line.dimmed());
        }
      }
      println!();
    }
  }

  if !found_any {
    println!("{}", "No matching content found.".yellow());
  } else {
    println!(
      "{}",
      "Tip: Use -c <num> to show more context lines (e.g., 'cr docs search <keyword> -c 20')".dimmed()
    );
    if filename_filter.is_none() {
      println!(
        "{}",
        "     Use -f <filename> to filter by file (e.g., 'cr docs search <keyword> -f syntax.md')".dimmed()
      );
    }
  }

  Ok(())
}

fn handle_agents(
  heading_queries: &[String],
  include_subheadings: bool,
  full: bool,
  with_lines: bool,
  force_refresh: bool,
) -> Result<(), String> {
  let (cache_path, refreshed) = ensure_agents_cache(force_refresh)?;
  if refreshed {
    if force_refresh {
      println!("{}", format!("Force refreshed Agents doc cache from: {AGENTS_DOC_URL}").dimmed());
    } else {
      println!("{}", format!("Refreshed Agents doc cache from: {AGENTS_DOC_URL}").dimmed());
    }
  }
  let content = fs::read_to_string(&cache_path).map_err(|e| format!("Failed to read Agents cache {cache_path:?}: {e}"))?;
  let byte_len = content.len();
  let line_len = content.lines().count();

  println!("{} {}", "Agent file:".dimmed(), cache_path.to_string_lossy().cyan());
  println!(
    "{} {} bytes, {} lines",
    "Agent length:".dimmed(),
    byte_len.to_string().cyan(),
    line_len.to_string().cyan()
  );

  let cache_display = cache_path.to_string_lossy().to_string();
  handle_read_content(ReadRenderOptions {
    display_title: "Agents.md",
    display_path: &cache_display,
    command_hint: "agents",
    no_match_error: "No heading matched in Agents.md. Run 'cr docs agents' to list available headings.",
    content: &content,
    heading_queries,
    include_subheadings,
    full,
    with_lines,
  })
}

fn handle_read(
  filename: &str,
  heading_queries: &[String],
  include_subheadings: bool,
  full: bool,
  with_lines: bool,
) -> Result<(), String> {
  let guide_docs = load_guidebook_docs()?;
  let doc = find_doc_by_filename(&guide_docs, filename)?;
  let result = handle_read_content(ReadRenderOptions {
    display_title: &doc.filename,
    display_path: &doc.path,
    command_hint: "read",
    no_match_error: "No heading matched in document.",
    content: &doc.content,
    heading_queries,
    include_subheadings,
    full,
    with_lines,
  });

  if result.is_err() && !heading_queries.is_empty() {
    return Err(format!(
      "No heading matched: {}. Use 'cr docs read {filename}' to list available headings.",
      heading_queries.join(", ")
    ));
  }

  result
}

fn handle_read_lines(filename: &str, start: usize, lines_to_read: usize) -> Result<(), String> {
  let guide_docs = load_guidebook_docs()?;

  let doc = find_doc_by_filename(&guide_docs, filename)?;

  let all_lines: Vec<&str> = doc.content.lines().collect();
  let total_lines = all_lines.len();
  let end = (start + lines_to_read).min(total_lines);

  println!("{} ({})", doc.filename.cyan().bold(), doc.path.dimmed());
  println!("{}", "=".repeat(60).dimmed());

  // Display lines with line numbers
  for (idx, line) in all_lines[start..end].iter().enumerate() {
    let line_num = start + idx + 1;
    println!("{} {}", format!("{line_num:4}:").dimmed(), line);
  }

  // Show tips
  println!();
  println!(
    "{}",
    format!("Lines {}-{} of {} (total {} lines)", start + 1, end, total_lines, total_lines).dimmed()
  );

  if end < total_lines {
    let remaining = total_lines - end;
    println!(
      "{}",
      format!("More content available ({remaining} lines remaining). Use -s {end} -n {lines_to_read} to continue reading.").yellow()
    );
  } else {
    println!("{}", "End of document.".green());
  }

  println!(
    "{}",
    "Tip: Use -s <start> -n <lines> to read specific range (e.g., 'cr docs read-lines file.md -s 20 -n 30')".dimmed()
  );

  Ok(())
}

fn handle_list() -> Result<(), String> {
  let guide_docs = load_guidebook_docs()?;

  println!("{}", "Available Guidebook Documentation:".bold());

  let mut docs: Vec<&GuideDoc> = guide_docs.values().collect();
  docs.sort_by_key(|d| &d.path);

  for doc in &docs {
    let preview = if doc.content.len() > 100 {
      format!("{}...", doc.content.lines().next().unwrap_or(""))
    } else {
      doc.content.lines().next().unwrap_or("").to_string()
    };

    println!("  {} - {}", doc.filename.cyan(), preview.dimmed());
  }

  println!("\n{} {} topics", "Total:".dimmed(), docs.len());
  println!("{}", "Use 'cr docs read <filename>' to list headings in a document".dimmed());
  println!(
    "{}",
    "    'cr docs read <filename> <heading-keyword>' to read matched sections".dimmed()
  );
  println!(
    "{}",
    "    'cr docs read-lines <filename> -s <start> -n <lines>' for line-based reading".dimmed()
  );
  println!("{}", "    'cr docs search <keyword>' to search content".dimmed());

  Ok(())
}

/// Check mode for a cirru code block in markdown.
///
/// - `cirru`          → Run: parse + preprocess + eval
/// - `cirru.no-run`   → NoRun: parse + preprocess (type-check), skip eval
/// - `cirru.no-check` → NoCheck: parse only (syntax validation)
#[derive(Debug, Clone, Copy, PartialEq)]
enum CirruCheckMode {
  Run,
  NoRun,
  NoCheck,
}

impl std::fmt::Display for CirruCheckMode {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    match self {
      CirruCheckMode::Run => write!(f, "run"),
      CirruCheckMode::NoRun => write!(f, "no-run"),
      CirruCheckMode::NoCheck => write!(f, "no-check"),
    }
  }
}

/// Extract cirru code blocks from markdown content.
/// Recognizes:  ```cirru  ```cirru.no-run  ```cirru.no-check
/// Returns (line_number, check_mode, code_content) triples.
fn extract_cirru_blocks(content: &str) -> Vec<(usize, CirruCheckMode, String)> {
  let mut blocks = Vec::new();
  let mut in_block = false;
  let mut in_non_cirru_block = false;
  let mut block_start_line = 0;
  let mut block_mode = CirruCheckMode::Run;
  let mut block_lines: Vec<&str> = Vec::new();

  for (idx, line) in content.lines().enumerate() {
    let trimmed = line.trim();
    if !in_block && !in_non_cirru_block && trimmed.starts_with("```") {
      if trimmed == "```cirru" {
        in_block = true;
        block_start_line = idx + 1; // 1-based
        block_mode = CirruCheckMode::Run;
        block_lines.clear();
      } else if trimmed == "```cirru.no-run" {
        in_block = true;
        block_start_line = idx + 1;
        block_mode = CirruCheckMode::NoRun;
        block_lines.clear();
      } else if trimmed == "```cirru.no-check" {
        in_block = true;
        block_start_line = idx + 1;
        block_mode = CirruCheckMode::NoCheck;
        block_lines.clear();
      } else {
        // other fenced block (```json, ```bash, etc.) — skip entirely
        in_non_cirru_block = true;
      }
    } else if (in_block || in_non_cirru_block) && trimmed == "```" {
      if in_block && !block_lines.is_empty() {
        blocks.push((block_start_line, block_mode, block_lines.join("\n")));
      }
      in_block = false;
      in_non_cirru_block = false;
    } else if in_block {
      block_lines.push(line);
    }
  }

  blocks
}

fn ensure_runtime_initialized() {
  static RUNTIME_INIT: Once = Once::new();
  RUNTIME_INIT.call_once(|| {
    calcit::builtins::effects::init_effects_states();
    #[cfg(not(target_arch = "wasm32"))]
    crate::injection::inject_platform_apis();
  });
}

fn module_folder() -> Result<PathBuf, String> {
  let home = std::env::var("HOME").map_err(|_| "Unable to get HOME environment variable".to_string())?;
  Ok(Path::new(&home).join(".config/calcit/modules/"))
}

fn display_path_with_default_modules(path: &str, default_modules: &Path) -> String {
  if let Ok(stripped) = Path::new(path).strip_prefix(default_modules) {
    format!("<mods>/{}", stripped.display())
  } else {
    path.to_owned()
  }
}

fn display_path_for_check_md(path: &str, default_modules: &Path, cwd: Option<&Path>) -> String {
  let raw = Path::new(path);
  if raw.is_absolute()
    && let Some(current_dir) = cwd
    && let Ok(stripped) = raw.strip_prefix(current_dir)
  {
    return stripped.display().to_string();
  }
  display_path_with_default_modules(path, default_modules)
}

fn load_shared_files_for_check_md(entry: &str, deps: &[String]) -> Result<HashMap<String, snapshot::FileInSnapShot>, String> {
  ensure_runtime_initialized();

  let entry_path = PathBuf::from(entry);
  let base_dir = entry_path.parent().unwrap_or(Path::new("."));
  let module_folder = module_folder()?;

  let mut shared_files: HashMap<String, snapshot::FileInSnapShot> = HashMap::new();

  for module_path in deps {
    let module_data = calcit::load_module(module_path, base_dir, &module_folder)?;
    for (k, v) in &module_data.files {
      if shared_files.contains_key(k) {
        return Err(format!("namespace `{k}` already exists when loading module `{module_path}`"));
      }
      shared_files.insert(k.to_owned(), v.to_owned());
    }
  }

  let core_snapshot = calcit::load_core_snapshot()?;
  for (k, v) in core_snapshot.files {
    shared_files.insert(k.to_owned(), v.to_owned());
  }

  Ok(shared_files)
}

fn build_entries_from_snapshot(snapshot: &snapshot::Snapshot) -> Result<ProgramEntries, String> {
  let config_init = snapshot.configs.init_fn.to_string();
  let config_reload = snapshot.configs.reload_fn.to_string();
  let (init_ns, init_def) = util::string::extract_ns_def(&config_init)?;
  let (reload_ns, reload_def) = util::string::extract_ns_def(&config_reload)?;

  Ok(ProgramEntries {
    init_fn: Arc::from(config_init),
    reload_fn: Arc::from(config_reload),
    init_def: Arc::from(init_def),
    init_ns: Arc::from(init_ns),
    reload_ns: Arc::from(reload_ns),
    reload_def: Arc::from(reload_def),
  })
}

fn prepare_program_for_snippet(shared_files: &HashMap<String, snapshot::FileInSnapShot>, code: &str) -> Result<ProgramEntries, String> {
  ensure_runtime_initialized();

  let mut snapshot = snapshot::Snapshot::default();
  let main_file = snapshot::create_file_from_snippet(code)?;
  snapshot.files.insert(String::from("app.main"), main_file);

  for (k, v) in shared_files {
    snapshot.files.insert(k.to_owned(), v.to_owned());
  }

  {
    let mut prgm = program::PROGRAM_CODE_DATA.write().map_err(|_| "open program data".to_string())?;
    *prgm = program::extract_program_data(&snapshot)?;
  }

  let check_warnings: &RefCell<Vec<LocatedWarning>> = &RefCell::new(vec![]);
  runner::preprocess::preprocess_ns_def(
    calcit::calcit::CORE_NS,
    calcit::calcit::BUILTIN_IMPLS_ENTRY,
    check_warnings,
    &CallStackList::default(),
  )
  .map_err(|e| e.msg)?;

  build_entries_from_snapshot(&snapshot)
}

fn run_check_only_in_process(entries: &ProgramEntries) -> Result<(), String> {
  let check_warnings: &RefCell<Vec<LocatedWarning>> = &RefCell::new(vec![]);

  runner::preprocess::preprocess_ns_def(&entries.init_ns, &entries.init_def, check_warnings, &CallStackList::default())
    .map_err(|failure| failure.msg)?;

  runner::preprocess::preprocess_ns_def(&entries.reload_ns, &entries.reload_def, check_warnings, &CallStackList::default())
    .map_err(|failure| failure.msg)?;

  let warnings = check_warnings.borrow();
  if !warnings.is_empty() {
    let mut lines = vec![format!("Warnings: ({} warnings)", warnings.len())];
    lines.extend(warnings.iter().map(|w| w.to_string()));
    return Err(lines.join("\n"));
  }

  Ok(())
}

fn run_eval_in_process(entries: &ProgramEntries) -> Result<(), String> {
  match calcit::run_program_with_docs(entries.init_ns.to_owned(), entries.init_def.to_owned(), &[]) {
    Ok(_) => Ok(()),
    Err(e) => {
      let mut lines: Vec<String> = vec![];
      if !e.warnings.is_empty() {
        lines.push(format!("Warnings: ({} warnings)", e.warnings.len()));
        lines.extend(e.warnings.iter().map(|w| w.to_string()));
      }
      lines.push(format!("Error: {}", e.msg));
      Err(lines.join("\n"))
    }
  }
}

fn run_parse_only_in_process(code: &str) -> Result<(), String> {
  cirru_parser::parse(code)
    .map(|_| ())
    .map_err(|e| format!("Error: Failed to parse code snippet: {e}"))
}

fn handle_check_md(file_path: &str, entry: &str, deps: &[String]) -> Result<(), String> {
  let content = fs::read_to_string(file_path).map_err(|e| format!("Failed to read file '{file_path}': {e}"))?;

  let blocks = extract_cirru_blocks(&content);

  if blocks.is_empty() {
    println!("{}", "No cirru code blocks found in the file.".yellow());
    return Ok(());
  }

  if !Path::new(entry).exists() {
    return Err(format!(
      "Entry file '{entry}' not found. Use -d to specify a valid entry .cirru file."
    ));
  }

  let shared_files = load_shared_files_for_check_md(entry, deps)?;

  let default_modules = module_folder()?;
  let current_dir = std::env::current_dir().ok();

  let entry_preview = display_path_for_check_md(entry, &default_modules, current_dir.as_deref());

  let deps_preview = if deps.is_empty() {
    "none".dimmed().to_string()
  } else {
    deps
      .iter()
      .map(|dep| display_path_for_check_md(dep, &default_modules, current_dir.as_deref()))
      .collect::<Vec<_>>()
      .join(", ")
      .dimmed()
      .to_string()
  };
  println!(
    "{} {} (entry: {}, deps: {})",
    "Checking".bold(),
    file_path.cyan(),
    entry_preview.dimmed(),
    deps_preview
  );
  println!("{}", "-".repeat(60).dimmed());

  let mut passed = 0;
  let mut failed = 0;
  let total = blocks.len();
  let run_count = blocks.iter().filter(|(_, mode, _)| *mode == CirruCheckMode::Run).count();
  let no_run_count = blocks.iter().filter(|(_, mode, _)| *mode == CirruCheckMode::NoRun).count();
  let no_check_count = blocks.iter().filter(|(_, mode, _)| *mode == CirruCheckMode::NoCheck).count();

  if run_count < no_check_count {
    println!(
      "{}",
      format!(
        "Tip: check-mode balance is skewed (cirru: {run_count}, cirru.no-run: {no_run_count}, cirru.no-check: {no_check_count}). Prefer `cirru` first, then `cirru.no-run`, and use `cirru.no-check` only when necessary."
      )
      .yellow()
    );
    println!("{}", "-".repeat(60).dimmed());
  }

  for (line_num, mode, code) in &blocks {
    // Show a brief preview of the code block
    let preview: String = code.lines().next().unwrap_or("").chars().take(60).collect();
    let preview_suffix = if code.lines().count() > 1 || preview.len() >= 60 {
      "..."
    } else {
      ""
    };

    let mode_label = match mode {
      CirruCheckMode::Run => "",
      CirruCheckMode::NoRun => "[no-run] ",
      CirruCheckMode::NoCheck => "[no-check] ",
    };

    let check_result = match mode {
      CirruCheckMode::Run => {
        let entries = prepare_program_for_snippet(&shared_files, code)?;
        run_eval_in_process(&entries)
      }
      CirruCheckMode::NoRun => {
        let entries = prepare_program_for_snippet(&shared_files, code)?;
        run_check_only_in_process(&entries)
      }
      CirruCheckMode::NoCheck => run_parse_only_in_process(code),
    };

    if check_result.is_ok() {
      passed += 1;
      println!(
        "  {} L{}: {}{}{}",
        "✓".green(),
        format!("{line_num}").dimmed(),
        mode_label.dimmed(),
        preview.dimmed(),
        preview_suffix.dimmed()
      );
    } else {
      failed += 1;
      let stderr = check_result.err().unwrap_or_else(|| "Error: Unknown error".to_string());
      println!(
        "  {} L{}: {}{}{}",
        "✗".red(),
        format!("{line_num}").yellow(),
        mode_label,
        preview,
        preview_suffix
      );

      for line in stderr.lines() {
        let lower = line.to_lowercase();
        if lower.contains("warn") || lower.contains("error") {
          println!("    {}", line.red());
        }
      }
    }
  }

  println!("{}", "-".repeat(60).dimmed());
  let summary = format!("Results: {total} blocks, {passed} passed, {failed} failed");
  if failed > 0 {
    println!("{}", summary.red().bold());
    Err(format!("{failed} code block(s) failed"))
  } else {
    println!("{}", summary.green().bold());
    Ok(())
  }
}
