use std::path::PathBuf;

use clap::{Parser, Subcommand};
use ebookm_core::{
    build_epub, inspect_source, load_manifest, render_init_manifest, validate_manifest,
};
use miette::{Context, IntoDiagnostic};

#[derive(Debug, Parser)]
#[command(
    name = "ebookm",
    version,
    about = "Compile Substack articles into a single EPUB"
)]
struct Cli {
    #[command(subcommand)]
    command: Commands,
}

#[derive(Debug, Subcommand)]
enum Commands {
    Build {
        #[arg(short, long)]
        manifest: PathBuf,
        #[arg(short, long)]
        output: Option<PathBuf>,
    },
    Validate {
        #[arg(short, long)]
        manifest: PathBuf,
    },
    Inspect {
        source: String,
        #[arg(long, default_value = "json")]
        format: String,
    },
    Init,
}

fn main() -> miette::Result<()> {
    let cli = Cli::parse();

    match cli.command {
        Commands::Build { manifest, output } => {
            let mut loaded = load_manifest(&manifest).into_diagnostic()?;
            if let Some(output) = output {
                loaded.output.path = output.display().to_string();
            }
            let warnings = validate_manifest(&loaded).into_diagnostic()?;
            for warning in warnings {
                eprintln!("warning: {warning}");
            }
            build_epub(&loaded, &manifest).into_diagnostic()?;
            println!("{}", loaded.output.path);
        }
        Commands::Validate { manifest } => {
            let loaded = load_manifest(&manifest).into_diagnostic()?;
            let warnings = validate_manifest(&loaded).into_diagnostic()?;
            for warning in warnings {
                println!("warning: {warning}");
            }
            println!("manifest is valid");
        }
        Commands::Inspect { source, format } => {
            let result = inspect_source(&source).into_diagnostic()?;
            if format == "json" {
                println!(
                    "{}",
                    serde_json::to_string_pretty(&result)
                        .into_diagnostic()
                        .wrap_err("failed to encode JSON")?
                );
            } else {
                println!("title: {}", result.title.unwrap_or_default());
                println!("author: {}", result.author.unwrap_or_default());
                println!("published: {}", result.published.unwrap_or_default());
                println!(
                    "canonical_url: {}",
                    result.canonical_url.unwrap_or_default()
                );
            }
        }
        Commands::Init => {
            print!("{}", render_init_manifest());
        }
    }

    Ok(())
}
