use anyhow::Context;
use anyhow::Result;
use cargo_metadata::MetadataCommand;
use clap::Parser;
use clap::Subcommand;
use std::path::Path;
use std::path::PathBuf;

pub mod autogen;
pub mod claude;
pub mod endpoint_coverage;
pub mod justfile;
pub mod marker;
pub mod mise;
pub mod policy;
pub mod readme;
pub mod release_plz;
pub mod schema;
pub mod sync;
pub mod verify;

#[derive(Parser, Debug)]
#[command(name = "xtask", about = "Repo maintenance tasks")]
struct Args {
    #[command(subcommand)]
    cmd: Cmd,
}

#[derive(Subcommand, Debug)]
enum Cmd {
    /// Sync README dependency versions inside autodeps markers
    ReadmeSync {
        /// Path to the README (defaults to repo root README.md)
        #[arg(long, default_value = "README.md")]
        path: PathBuf,
        /// Dry-run: print diffable output to stdout but don't write
        #[arg(long)]
        dry_run: bool,
        /// Check mode: fail if README is out of sync (for CI)
        #[arg(long)]
        check: bool,
    },
    /// Sync autogenerated content (CLAUDE.md files, release-plz.toml)
    Sync {
        /// Dry-run: print what would change but don't write
        #[arg(long)]
        dry_run: bool,
        /// Check mode: fail if any files are out of sync (for CI)
        #[arg(long)]
        check: bool,
    },
    /// Verify metadata, policy rules, and generated file freshness
    Verify {
        /// Check mode: also verify generated files are up to date
        #[arg(long)]
        check: bool,
    },
    /// Check SDK endpoint coverage against server `OpenAPI` spec
    EndpointCoverage {
        /// Output results as JSON
        #[arg(long, default_value_t = false)]
        json: bool,
        /// Fail if coverage is incomplete (for CI)
        #[arg(long, default_value_t = false)]
        check: bool,
    },
}

fn strict_mode() -> bool {
    matches!(std::env::var("AUTODEPS_STRICT"), Ok(v) if v == "1" || v.eq_ignore_ascii_case("true"))
}

fn main() -> Result<()> {
    let args = Args::parse();
    match args.cmd {
        Cmd::ReadmeSync {
            path,
            dry_run,
            check,
        } => readme_sync(&path, dry_run, check),
        Cmd::Sync { dry_run, check } => sync::run(dry_run, check),
        Cmd::Verify { check } => verify::run(check),
        Cmd::EndpointCoverage { json, check } => endpoint_coverage::run(json, check),
    }
}

fn readme_sync(path: &Path, dry_run: bool, check: bool) -> Result<()> {
    let metadata = MetadataCommand::new()
        .no_deps()
        .exec()
        .context("Failed to run `cargo metadata`")?;
    let strict = strict_mode();

    readme::sync_root_readme_cli(path, &metadata, dry_run, check, strict)
}
