//! Aphoria CLI - A code-level truth linter powered by Episteme
//!
//! CLI binaries use println! for user-facing output (not tracing)
#![allow(clippy::print_stdout, clippy::print_stderr)]

use std::path::PathBuf;
use std::process::ExitCode;

use clap::{Parser, Subcommand};

use aphoria::{run_scan, AcknowledgeArgs, AphoriaConfig, ScanArgs};

/// A code-level truth linter powered by Episteme.
///
/// Aphoria scans a codebase, extracts the decisions embedded in config and code,
/// and checks them against authoritative sources. It finds the places where what
/// your code *does* contradicts what the specs *say*.
#[derive(Parser)]
#[command(name = "aphoria")]
#[command(version, about, long_about = None)]
struct Cli {
    /// Path to aphoria.toml configuration file
    #[arg(short, long, global = true)]
    config: Option<PathBuf>,

    #[command(subcommand)]
    command: Commands,
}

#[derive(Subcommand)]
enum Commands {
    /// Scan a project for epistemic drift
    Scan {
        /// Path to the project root to scan
        #[arg(default_value = ".")]
        path: PathBuf,

        /// Output format: table, json, sarif, markdown
        #[arg(short, long, default_value = "table")]
        format: String,

        /// Exit with non-zero code if conflicts found
        #[arg(long)]
        exit_code: bool,
    },

    /// Acknowledge a conflict (mark as intentional)
    Ack {
        /// The concept path to acknowledge
        concept_path: String,

        /// Reason for acknowledgment
        #[arg(short, long)]
        reason: String,
    },

    /// Set the current scan as the baseline
    Baseline,

    /// Show changes since last baseline
    Diff,

    /// Show current scan status
    Status,

    /// Initialize Aphoria with authoritative corpus
    Init,
}

#[tokio::main]
async fn main() -> ExitCode {
    // Initialize tracing for internal logging
    tracing_subscriber::fmt::init();

    let cli = Cli::parse();

    // Load configuration
    let config = match load_config(cli.config.as_deref()) {
        Ok(cfg) => cfg,
        Err(e) => {
            eprintln!("Error loading configuration: {e}");
            return ExitCode::from(3);
        }
    };

    match cli.command {
        Commands::Scan { path, format, exit_code } => {
            let args = ScanArgs { path, format, exit_code_enabled: exit_code };

            match run_scan(args, &config).await {
                Ok(result) => {
                    println!("{}", result.display());

                    if exit_code && result.has_blocks() {
                        ExitCode::from(2)
                    } else if exit_code && result.has_flags() {
                        ExitCode::from(1)
                    } else {
                        ExitCode::SUCCESS
                    }
                }
                Err(e) => {
                    eprintln!("Scan error: {e}");
                    ExitCode::from(3)
                }
            }
        }

        Commands::Ack { concept_path, reason } => {
            let args = AcknowledgeArgs { concept_path, reason };

            match aphoria::acknowledge(args, &config).await {
                Ok(()) => {
                    println!("Conflict acknowledged.");
                    ExitCode::SUCCESS
                }
                Err(e) => {
                    eprintln!("Acknowledge error: {e}");
                    ExitCode::from(3)
                }
            }
        }

        Commands::Baseline => match aphoria::set_baseline(&config).await {
            Ok(()) => {
                println!("Baseline set.");
                ExitCode::SUCCESS
            }
            Err(e) => {
                eprintln!("Baseline error: {e}");
                ExitCode::from(3)
            }
        },

        Commands::Diff => match aphoria::show_diff(&config).await {
            Ok(output) => {
                println!("{output}");
                ExitCode::SUCCESS
            }
            Err(e) => {
                eprintln!("Diff error: {e}");
                ExitCode::from(3)
            }
        },

        Commands::Status => match aphoria::show_status(&config).await {
            Ok(output) => {
                println!("{output}");
                ExitCode::SUCCESS
            }
            Err(e) => {
                eprintln!("Status error: {e}");
                ExitCode::from(3)
            }
        },

        Commands::Init => match aphoria::initialize(&config).await {
            Ok(()) => {
                println!("Aphoria initialized. Run `aphoria scan <project>` to begin.");
                ExitCode::SUCCESS
            }
            Err(e) => {
                eprintln!("Init error: {e}");
                ExitCode::from(3)
            }
        },
    }
}

/// Load configuration from file or use defaults.
fn load_config(path: Option<&std::path::Path>) -> Result<AphoriaConfig, aphoria::AphoriaError> {
    if let Some(p) = path {
        AphoriaConfig::from_file(p)
    } else {
        // Try default locations
        let default_paths = ["aphoria.toml", ".aphoria/config.toml"];
        for default in default_paths {
            let p = std::path::Path::new(default);
            if p.exists() {
                return AphoriaConfig::from_file(p);
            }
        }
        // No config file found, use defaults
        Ok(AphoriaConfig::default())
    }
}
