use aignt_mint_scoring::{fetch_token_security, rugcheck::fetch_rugcheck_report, score, scorer};
/// Solana Mint Security Scorer
///
/// CLI for calculating comprehensive security scores for Solana tokens
/// based on Birdeye API data.
///
/// Score Range: 0-100
/// - 90-100: Excellent (Very Safe)
/// - 75-89:  Good (Generally Safe)
/// - 60-74:  Moderate (Exercise Caution)
/// - 40-59:  Poor (High Risk)
/// - 0-39:   Critical (Very High Risk / Likely Scam)
use birdeye_client::client::{BirdeyeClient, BirdeyeProvider};
use reqwest::Client as ReqwestClient;

use anyhow::Result;
use clap::Parser;
use colored::*;

#[derive(Parser, Debug)]
#[command(author, version, about = "Solana mint security scorer", long_about = None)]
struct Args {
    /// Token mint address to analyze
    #[arg(short, long)]
    mint: String,

    /// Birdeye API key (overrides DATA_PROVIDER_API_KEY from .env)
    #[arg(short = 'a', long)]
    api_key: Option<String>,

    /// API provider: "birdeye" or "uniblock" (overrides DATA_PROVIDER from .env)
    #[arg(long)]
    provider: Option<String>,

    /// Output format: text (default) or json
    #[arg(short, long, default_value = "text")]
    format: String,

    /// Enable verbose logging of API responses
    #[arg(short = 'v', long)]
    verbose: bool,
}

#[tokio::main]
async fn main() -> Result<()> {
    dotenvy::dotenv().ok();

    let args = Args::parse();

    let api_key = args
        .api_key
        .or_else(|| std::env::var("DATA_PROVIDER_API_KEY").ok())
        .ok_or_else(|| {
            anyhow::anyhow!(
                "API key not provided. Use --api-key or set DATA_PROVIDER_API_KEY environment variable"
            )
        })?;

    let provider_str = args
        .provider
        .or_else(|| std::env::var("DATA_PROVIDER").ok())
        .unwrap_or_else(|| "birdeye".to_string());
    let provider = match provider_str.to_lowercase().as_str() {
        "uniblock" => BirdeyeProvider::Uniblock,
        _ => BirdeyeProvider::Birdeye,
    };

    println!(
        "{}",
        "=== Solana Mint Security Scorer ===".bright_cyan().bold()
    );
    println!("Analyzing mint: {}\n", args.mint.bright_white());

    let client = BirdeyeClient::new(&api_key, provider, None)?;

    println!("{}", "Fetching security data...".dimmed());
    let security = fetch_token_security(&client, &args.mint).await?;

    if args.verbose {
        println!(
            "\n{}\n{}\n{}\n",
            "=== TOKEN SECURITY API RESPONSE ===".bright_cyan().bold(),
            serde_json::to_string_pretty(&security)?,
            "=== END TOKEN SECURITY RESPONSE ===".bright_cyan().bold()
        );
    }

    println!("{}", "Fetching rugcheck LP data...".dimmed());
    let rc_client = ReqwestClient::new();
    let rugcheck = match fetch_rugcheck_report(&rc_client, &args.mint).await {
        Ok(r) => {
            if args.verbose {
                println!(
                    "\n{}\nlp_locked_pct: {:?}, score: {:?}, risks: {}\n",
                    "=== RUGCHECK RESPONSE ===".bright_cyan().bold(),
                    r.lp_locked_pct,
                    r.score,
                    r.risks.len(),
                );
            }
            Some(r)
        }
        Err(e) => {
            println!(
                "{} {}",
                "⚠ rugcheck.xyz unavailable (liquidity score set to 25):".yellow(),
                e.to_string().dimmed()
            );
            None
        }
    };

    let score = score(&args.mint, &security, rugcheck.as_ref());

    if args.verbose {
        println!(
            "\n{}\n{}\n{}",
            "=== SCORE RESULT ===".bright_cyan().bold(),
            serde_json::to_string_pretty(&score)?,
            "=== END SCORE RESULT ===".bright_cyan().bold(),
        );
    }

    match args.format.as_str() {
        "json" => {
            println!("{}", serde_json::to_string_pretty(&score)?);
        }
        _ => {
            print_text_report(&score);
        }
    }

    Ok(())
}

fn print_text_report(score: &scorer::Score) {
    println!(
        "\n{}",
        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━".bright_black()
    );

    if score.hard_stop_triggered {
        println!(
            "\n{}",
            "🛑 HARD STOP VIOLATIONS DETECTED 🛑".bright_red().bold()
        );
        println!(
            "{}",
            "This token has CRITICAL security issues that are deal-breakers:"
                .red()
                .bold()
        );
        println!();

        for violation in &score.hard_stop_violations {
            let severity_color = match violation.severity.as_str() {
                "Critical" => "CRITICAL".bright_red().bold(),
                "Severe" => "SEVERE".red().bold(),
                "Major" => "MAJOR".yellow().bold(),
                _ => "ISSUE".red(),
            };

            println!(
                "{} [{}]",
                violation.message.bright_red().bold(),
                severity_color
            );
            println!("{}", violation.description.dimmed());
            println!();
        }

        println!(
            "{}",
            "⚠️  Investment in this token is NOT RECOMMENDED ⚠️"
                .bright_red()
                .bold()
        );
        println!(
            "{}",
            "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━".bright_black()
        );
        println!();
    }

    let score_str = format!("{:.1}/100", score.score);
    let colored_score = match score.risk_level {
        scorer::RiskLevel::Excellent => score_str.bright_green().bold(),
        scorer::RiskLevel::Good => score_str.green(),
        scorer::RiskLevel::Moderate => score_str.yellow(),
        scorer::RiskLevel::Poor => score_str.red(),
        scorer::RiskLevel::Critical => score_str.bright_red().bold(),
    };

    println!("{} {}", "OVERALL SECURITY SCORE:".bold(), colored_score);

    if score.hard_stop_triggered {
        println!("{}", "(Score capped due to hard stop violations)".dimmed());
    }

    println!(
        "{} {} ({})",
        "LAUNCH PLATFORM:".bold(),
        score.launch_platform.bright_white(),
        score.platform_trust_level.dimmed()
    );

    let risk_label = format!("{:?}", score.risk_level).to_uppercase();
    let colored_risk = match score.risk_level {
        scorer::RiskLevel::Excellent => risk_label.bright_green().bold(),
        scorer::RiskLevel::Good => risk_label.green(),
        scorer::RiskLevel::Moderate => risk_label.yellow(),
        scorer::RiskLevel::Poor => risk_label.red(),
        scorer::RiskLevel::Critical => risk_label.bright_red().bold(),
    };
    println!("{} {}", "RISK LEVEL:".bold(), colored_risk);

    println!("\n{}", "Category Breakdown:".bold().underline());

    let categories: &[(&str, f64, f64, &Vec<String>)] = &[
        (
            "Authority Controls:",
            score.score_breakdown.authority,
            25.0,
            &score.authority_reasons,
        ),
        (
            "Holder Distribution:",
            score.score_breakdown.holder_distribution,
            20.0,
            &score.holder_reasons,
        ),
        (
            "Metadata & Flags:",
            score.score_breakdown.metadata,
            15.0,
            &score.metadata_reasons,
        ),
        (
            "Trust Signals:",
            score.score_breakdown.trust,
            15.0,
            &score.trust_reasons,
        ),
        (
            "Liquidity:",
            score.score_breakdown.liquidity,
            25.0,
            &score.liquidity_reasons,
        ),
    ];

    for (label, cat_score, max, reasons) in categories {
        println!("  {:<22} {:.1}/{:.0}", label.bright_white(), cat_score, max);
        for reason in *reasons {
            println!("    {}", reason.dimmed());
        }
    }

    if !score.positive_signals.is_empty() {
        println!("\n{}", "Positive Signals:".green().bold());
        for signal in &score.positive_signals {
            println!("  {}", signal.green());
        }
    }

    if !score.warnings.is_empty() {
        println!("\n{}", "Warnings:".red().bold());
        for warning in &score.warnings {
            if warning.contains("CRITICAL") {
                println!("  {}", warning.bright_red().bold());
            } else {
                println!("  {}", warning.yellow());
            }
        }
    }

    println!("\n{}", "Key Metrics:".bold().underline());
    println!(
        "  Mint Authority Revoked:   {}",
        format_bool(score.details.mint_authority_revoked)
    );
    println!(
        "  Freeze Authority Revoked: {}",
        format_bool(score.details.freeze_authority_revoked)
    );
    println!(
        "  Mutable Metadata:         {}",
        format_bool_inverted(score.details.mutable_metadata)
    );
    println!(
        "  Top 10 Holders:           {:.1}%",
        score.details.top10_holder_percent
    );
    println!(
        "  Creator Holdings:         {:.2}%",
        score.details.creator_percentage
    );
    println!(
        "  Jupiter Strict List:      {}",
        format_bool(score.details.jup_strict_list)
    );
    println!(
        "  Fake Token:               {}",
        format_bool_inverted(score.details.is_fake_token)
    );

    println!(
        "\n{}",
        "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━".bright_black()
    );
}

fn format_bool(value: bool) -> ColoredString {
    if value {
        "✓ Yes".green()
    } else {
        "✗ No".red()
    }
}

fn format_bool_inverted(value: bool) -> ColoredString {
    if value {
        "✗ Yes".red()
    } else {
        "✓ No".green()
    }
}
