//! CLI definition and argument types.

use clap::{Parser, Subcommand, ValueEnum};
use stemedb_ontology::{client::StemeClient, dto::LensQueryDto};

use crate::commands;

/// steme-pharma: Self-serve CLI for exploring GLP-1 drug data in StemeDB.
#[derive(Parser, Debug)]
#[command(name = "steme-pharma")]
#[command(version, about, long_about = None)]
pub struct Cli {
    /// StemeDB API URL
    #[arg(long, env = "STEMEDB_URL", default_value = "http://localhost:18180", global = true)]
    pub stemedb_url: String,

    /// Output format
    #[arg(long, short, default_value = "table", global = true, value_enum)]
    pub format: OutputFormat,

    /// Enable verbose logging
    #[arg(long, short, global = true)]
    pub verbose: bool,

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

impl Cli {
    /// Execute the CLI command.
    pub async fn run(self) -> Result<(), Box<dyn std::error::Error>> {
        // Initialize tracing
        let filter = if self.verbose { "debug" } else { "warn" };
        tracing_subscriber::fmt().with_env_filter(filter).init();

        let client = StemeClient::new(&self.stemedb_url);

        match self.command {
            Commands::Ingest(args) => commands::run_ingest(&client, args).await,
            Commands::Query(args) => commands::run_query(&client, args, self.format).await,
            Commands::Compare(args) => commands::run_compare(&client, args, self.format).await,
            Commands::Explore(args) => commands::run_explore(&client, args, self.format).await,
            Commands::Validate(args) => commands::run_validate(args, self.format).await,
        }
    }
}

#[derive(Subcommand, Debug)]
pub enum Commands {
    /// Ingest FDA drug data into StemeDB
    Ingest(IngestArgs),

    /// Query assertions with conflict analysis
    Query(QueryArgs),

    /// Compare two subjects side-by-side
    Compare(CompareArgs),

    /// List all predicates for a subject
    Explore(ExploreArgs),

    /// Validate subject/predicate against domain schema
    Validate(ValidateArgs),
}

#[derive(Parser, Debug)]
pub struct IngestArgs {
    /// Drugs to ingest (comma-separated, e.g., "semaglutide,tirzepatide")
    #[arg(default_value = "semaglutide")]
    pub drugs: String,

    /// Include mock conflict data for demo
    #[arg(long)]
    pub with_conflicts: bool,

    /// Skip FDA API calls (only use mock data)
    #[arg(long)]
    pub mock_only: bool,
}

#[derive(Parser, Debug)]
pub struct QueryArgs {
    /// Subject to query (e.g., "Semaglutide:Type2Diabetes")
    pub subject: String,

    /// Predicate to query (e.g., "nausea_rate")
    pub predicate: String,

    /// Query mode: skeptic (default), layered, or a lens name
    #[arg(long, short, default_value = "skeptic")]
    pub mode: QueryMode,
}

#[derive(Parser, Debug)]
pub struct CompareArgs {
    /// First subject to compare
    pub subject1: String,

    /// Second subject to compare
    pub subject2: String,

    /// Predicate to compare on
    #[arg(long, short)]
    pub predicate: String,
}

#[derive(Parser, Debug)]
pub struct ExploreArgs {
    /// Subject to explore
    pub subject: String,
}

#[derive(Parser, Debug)]
pub struct ValidateArgs {
    /// Subject to validate (e.g., "Semaglutide:Type2Diabetes")
    pub subject: String,

    /// Predicate to validate (e.g., "hba1c_change_percent")
    pub predicate: String,
}

#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum OutputFormat {
    /// Pretty table output
    Table,
    /// JSON output
    Json,
}

#[derive(Debug, Clone)]
pub enum QueryMode {
    /// Use the Skeptic lens for conflict analysis
    Skeptic,
    /// Use the LayeredConsensus lens for per-tier view
    Layered,
    /// Use a specific lens (Recency, Consensus, etc.)
    Lens(LensQueryDto),
}

impl std::str::FromStr for QueryMode {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "skeptic" => Ok(QueryMode::Skeptic),
            "layered" => Ok(QueryMode::Layered),
            "recency" => Ok(QueryMode::Lens(LensQueryDto::Recency)),
            "consensus" => Ok(QueryMode::Lens(LensQueryDto::Consensus)),
            "confidence" => Ok(QueryMode::Lens(LensQueryDto::Confidence)),
            "authority" => Ok(QueryMode::Lens(LensQueryDto::Authority)),
            "voteawareconsensus" => Ok(QueryMode::Lens(LensQueryDto::VoteAwareConsensus)),
            "trustawareauthority" => Ok(QueryMode::Lens(LensQueryDto::TrustAwareAuthority)),
            "epochaware" => Ok(QueryMode::Lens(LensQueryDto::EpochAware)),
            _ => Err(format!(
                "Unknown mode '{}'. Valid: skeptic, layered, recency, consensus, confidence, authority",
                s
            )),
        }
    }
}
