/// Hard Stop Security Checks
///
/// These are critical security issues that should immediately disqualify a token
/// or result in an automatic failing score, regardless of other metrics.
///
/// Platform-aware: known launchpads with bonding curve mechanics (Pump.fun, etc.)
/// skip holder concentration checks because the protocol contract holds the unsold
/// supply — concentration in that context is expected, not malicious.
use crate::platform::{LaunchPlatform, PlatformProfile};
use crate::rugcheck::RugcheckReport;
use birdeye_client::defi::types::BirdeyeTokenSecurity;

/// Result of hard stop checks
#[derive(Debug, Clone)]
pub struct HardStopResult {
    pub failed: bool,
    pub violations: Vec<HardStopViolation>,
    pub override_score: Option<f64>,
}

#[derive(Debug, Clone)]
pub struct HardStopViolation {
    pub severity: HardStopSeverity,
    pub category: String,
    pub message: String,
    pub description: String,
}

#[derive(Debug, Clone, PartialEq)]
pub enum HardStopSeverity {
    /// Immediate disqualification — score forced to 5
    Critical,
    /// Severe issue — score capped at 20
    Severe,
    /// Major issue — score capped at 34
    Major,
    /// Flagged for review — hard stop triggered but score not capped
    Warning,
}

impl HardStopResult {
    pub fn passed() -> Self {
        Self {
            failed: false,
            violations: Vec::new(),
            override_score: None,
        }
    }

    pub fn new(violations: Vec<HardStopViolation>) -> Self {
        if violations.is_empty() {
            return Self::passed();
        }

        let worst_severity = violations
            .iter()
            .map(|v| &v.severity)
            .min_by_key(|s| match s {
                HardStopSeverity::Critical => 0,
                HardStopSeverity::Severe => 1,
                HardStopSeverity::Major => 2,
                HardStopSeverity::Warning => 3,
            })
            .unwrap();

        // Override scores scaled to the new 75-point maximum:
        // Critical → 5, Severe → 20, Major → 34
        let override_score = match worst_severity {
            HardStopSeverity::Critical => Some(5.0),
            HardStopSeverity::Severe => Some(20.0),
            HardStopSeverity::Major => Some(34.0),
            HardStopSeverity::Warning => None,
        };

        Self {
            failed: true,
            violations,
            override_score,
        }
    }
}

/// Check all hard stop conditions.
///
/// Pass `rugcheck = Some(report)` to include the liquidity hard stop (LP locked = 0%).
/// When `rugcheck = None` the liquidity check is skipped (backward-compatible).
pub fn check_hard_stops(
    security: &BirdeyeTokenSecurity,
    profile: &PlatformProfile,
    rugcheck: Option<&RugcheckReport>,
) -> HardStopResult {
    let mut violations = Vec::new();

    violations.extend(check_platform_hard_stops(profile));
    violations.extend(check_critical_hard_stops(security));

    if !profile.skip_holder_hard_stops {
        violations.extend(check_holder_hard_stops(security));
    }

    if let Some(report) = rugcheck {
        violations.extend(check_liquidity_hard_stops(report));
    }

    HardStopResult::new(violations)
}

/// Check whether the liquidity pool is locked at all.
///
/// A `lp_locked_pct` of exactly 0 (or missing) means the creator can pull all
/// liquidity at any time — this is a Critical hard stop.
pub fn check_liquidity_hard_stops(report: &RugcheckReport) -> Vec<HardStopViolation> {
    let lp_locked_pct = report.lp_locked_pct.unwrap_or(0.0);
    if lp_locked_pct > 0.0 {
        return Vec::new();
    }

    vec![HardStopViolation {
        severity: HardStopSeverity::Critical,
        category: "Liquidity".to_string(),
        message: "🛑 HARD STOP: Liquidity pool is not locked (0%)".to_string(),
        description: "Zero percent of the liquidity pool is locked. The creator can remove all \
                     liquidity at any time, taking all investor funds. This is the textbook rug \
                     pull setup and an immediate disqualification."
            .to_string(),
    }]
}

fn check_platform_hard_stops(profile: &PlatformProfile) -> Vec<HardStopViolation> {
    if profile.platform != LaunchPlatform::Unknown {
        return Vec::new();
    }

    vec![HardStopViolation {
        severity: HardStopSeverity::Warning,
        category: "Platform".to_string(),
        message: "⚠️ HARD STOP: Launch platform not identified".to_string(),
        description: "This token was not created through a known, verified launch platform. \
                     Unidentified deployers receive no platform-level trust — the token's \
                     origin, mechanics, and supply distribution cannot be attributed to an \
                     audited contract. Manual verification of the deployer and token mechanics \
                     is required before considering investment."
            .to_string(),
    }]
}

fn check_critical_hard_stops(security: &BirdeyeTokenSecurity) -> Vec<HardStopViolation> {
    let mut violations = Vec::new();

    if security.non_transferable.unwrap_or(false) {
        violations.push(HardStopViolation {
            severity: HardStopSeverity::Critical,
            category: "Transferability".to_string(),
            message: "🛑 HARD STOP: Token is non-transferable".to_string(),
            description: "This token has the non-transferable flag set, meaning it cannot be \
                         transferred or traded. This makes it effectively worthless for trading \
                         purposes. This is an immediate disqualification."
                .to_string(),
        });
    }

    if security.fake_token.unwrap_or(false) {
        violations.push(HardStopViolation {
            severity: HardStopSeverity::Critical,
            category: "Legitimacy".to_string(),
            message: "🛑 HARD STOP: Token flagged as FAKE by Birdeye".to_string(),
            description: "Birdeye's security systems have explicitly flagged this token as fake \
                         or fraudulent. This indicates it's likely a scam or copycat token. \
                         Immediate disqualification."
                .to_string(),
        });
    }

    let mint_authority_revoked = match &security.owner_address {
        None => true,
        Some(s) => s == "null" || s.is_empty(),
    };

    if !mint_authority_revoked {
        violations.push(HardStopViolation {
            severity: HardStopSeverity::Critical,
            category: "Authority Control".to_string(),
            message: "🛑 HARD STOP: Mint authority is NOT revoked".to_string(),
            description: "The token creator retains mint authority, allowing them to create \
                         unlimited new tokens at any time. This can be used to dilute existing \
                         holders' value to zero through infinite inflation. This is a fundamental \
                         security failure and immediate red flag."
                .to_string(),
        });
    }

    violations
}

fn check_holder_hard_stops(security: &BirdeyeTokenSecurity) -> Vec<HardStopViolation> {
    let mut violations = Vec::new();

    let creator_pct = security.creator_percentage.unwrap_or(0.0);
    if creator_pct > 50.0 {
        violations.push(HardStopViolation {
            severity: HardStopSeverity::Severe,
            category: "Holder Distribution".to_string(),
            message: format!("🛑 HARD STOP: Creator holds {:.1}% of supply", creator_pct),
            description: format!(
                "The token creator holds {:.1}% of the total supply. This extreme concentration \
                 means the creator can single-handedly crash the token price at any time. \
                 Classic rug pull setup. Tokens with >50% creator holdings are not investable.",
                creator_pct
            ),
        });
    }

    let top10_pct = security.top10_holder_percent.unwrap_or(100.0);
    if top10_pct > 90.0 {
        violations.push(HardStopViolation {
            severity: HardStopSeverity::Severe,
            category: "Holder Distribution".to_string(),
            message: format!(
                "🛑 HARD STOP: Top 10 holders control {:.1}% of supply",
                top10_pct
            ),
            description: format!(
                "The top 10 wallet addresses control {:.1}% of the token supply. This extreme \
                 concentration means price is entirely controlled by a tiny group who can \
                 coordinate dumps. Any holder outside the top 10 is at extreme risk.",
                top10_pct
            ),
        });
    }

    if creator_pct > 30.0 && creator_pct <= 50.0 {
        violations.push(HardStopViolation {
            severity: HardStopSeverity::Major,
            category: "Holder Distribution".to_string(),
            message: format!("⚠️ HARD STOP: Creator holds {:.1}% of supply", creator_pct),
            description: format!(
                "The creator holds {:.1}% of supply. While not majority control, this is still \
                 a very high percentage that could be dumped to crash the price. Reputable \
                 projects typically have creator holdings <10%.",
                creator_pct
            ),
        });
    }

    if top10_pct > 70.0 && top10_pct <= 90.0 {
        violations.push(HardStopViolation {
            severity: HardStopSeverity::Major,
            category: "Holder Distribution".to_string(),
            message: format!("⚠️ HARD STOP: Top 10 holders control {:.1}%", top10_pct),
            description: format!(
                "Top 10 holders control {:.1}% of supply. This high concentration creates \
                 significant manipulation and dump risk. Healthy tokens typically have <50% \
                 in top 10 holders.",
                top10_pct
            ),
        });
    }

    let freeze_authority_revoked = match &security.freeze_authority {
        None => true,
        Some(s) => s == "null" || s.is_empty(),
    };

    if !freeze_authority_revoked {
        violations.push(HardStopViolation {
            severity: HardStopSeverity::Major,
            category: "Authority Control".to_string(),
            message: "⚠️ HARD STOP: Freeze authority is NOT revoked".to_string(),
            description: "The token creator can freeze individual token accounts at will, \
                         preventing transfers. While not as severe as mint authority, this \
                         allows the creator to selectively freeze accounts, potentially \
                         targeting specific holders or preventing exits during dumps."
                .to_string(),
        });
    }

    violations
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::platform::PlatformProfile;

    #[test]
    fn test_non_transferable_hard_stop() {
        let mut security = BirdeyeTokenSecurity::default();
        security.non_transferable = Some(true);

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        assert!(result.failed);
        assert_eq!(result.override_score, Some(5.0));
        assert!(
            result
                .violations
                .iter()
                .any(|v| v.message.contains("non-transferable"))
        );
    }

    #[test]
    fn test_fake_token_hard_stop() {
        let mut security = BirdeyeTokenSecurity::default();
        security.fake_token = Some(true);

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        assert!(result.failed);
        assert_eq!(result.override_score, Some(5.0));
        assert!(result.violations.iter().any(|v| v.message.contains("FAKE")));
    }

    #[test]
    fn test_mint_authority_hard_stop() {
        let mut security = BirdeyeTokenSecurity::default();
        security.owner_address = Some("ENVeHDjAJZWidPPdVUDUDSFMYvYHFHKEAS7oj71Nwm7S".to_string());

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        assert!(result.failed);
        assert!(
            result
                .violations
                .iter()
                .any(|v| v.message.contains("Mint authority"))
        );
    }

    #[test]
    fn test_extreme_creator_holdings() {
        let mut security = BirdeyeTokenSecurity::default();
        security.creator_percentage = Some(60.0);
        security.owner_address = None;
        security.non_transferable = Some(false);
        security.fake_token = Some(false);

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        assert!(result.failed);
        assert_eq!(result.override_score, Some(20.0));
    }

    #[test]
    fn test_no_hard_stops_on_known_platform() {
        let mut security = BirdeyeTokenSecurity::default();
        security.non_transferable = Some(false);
        security.fake_token = Some(false);
        security.creator_percentage = Some(1.0);
        security.top10_holder_percent = Some(20.0);
        security.owner_address = None;
        security.freeze_authority = Some("null".to_string());

        let pumpfun = crate::platform::detect_platform("mintaddresspump", &security);
        let result = check_hard_stops(&security, &pumpfun, None);

        assert!(!result.failed);
        assert_eq!(result.violations.len(), 0);
    }

    #[test]
    fn test_holder_concentration_triggers() {
        let mut security = BirdeyeTokenSecurity::default();
        security.top10_holder_percent = Some(100.0);
        security.owner_address = None;

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        assert!(result.failed);
        assert_eq!(result.override_score, Some(20.0));
        assert!(
            result
                .violations
                .iter()
                .any(|v| v.message.contains("Top 10 holders"))
        );
    }

    #[test]
    fn test_multiple_hard_stops_worst_severity_wins() {
        let mut security = BirdeyeTokenSecurity::default();
        security.non_transferable = Some(true);
        security.creator_percentage = Some(35.0);

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        assert!(result.failed);
        assert_eq!(result.override_score, Some(5.0));
        assert!(result.violations.len() >= 2);
    }

    #[test]
    fn test_pumpfun_profile_skips_holder_concentration_hard_stop() {
        let mut security = BirdeyeTokenSecurity::default();
        security.top10_holder_percent = Some(100.0);
        security.owner_address = None;
        security.non_transferable = Some(false);
        security.fake_token = Some(false);

        let pumpfun = crate::platform::detect_platform("mintaddresspump", &security);
        let result = check_hard_stops(&security, &pumpfun, None);

        assert!(
            !result.failed,
            "Pump.fun bonding curve should pass holder checks"
        );
        assert!(
            result
                .violations
                .iter()
                .all(|v| v.category != "Holder Distribution")
        );
    }

    #[test]
    fn test_pumpfun_profile_still_catches_critical_stops() {
        let mut security = BirdeyeTokenSecurity::default();
        security.top10_holder_percent = Some(100.0);
        security.fake_token = Some(true);
        security.owner_address = None;

        let pumpfun = crate::platform::detect_platform("mintaddresspump", &security);
        let result = check_hard_stops(&security, &pumpfun, None);

        assert!(result.failed);
        assert!(result.violations.iter().any(|v| v.message.contains("FAKE")));
    }

    #[test]
    fn test_pumpfun_profile_still_catches_mint_authority() {
        let mut security = BirdeyeTokenSecurity::default();
        security.top10_holder_percent = Some(100.0);
        security.owner_address = Some("SomeMintAuthorityAddress".to_string());
        security.fake_token = Some(false);
        security.non_transferable = Some(false);

        let pumpfun = crate::platform::detect_platform("mintaddresspump", &security);
        let result = check_hard_stops(&security, &pumpfun, None);

        assert!(result.failed);
        assert!(
            result
                .violations
                .iter()
                .any(|v| v.message.contains("Mint authority"))
        );
    }

    #[test]
    fn test_unknown_platform_triggers_platform_hard_stop() {
        let mut security = BirdeyeTokenSecurity::default();
        security.non_transferable = Some(false);
        security.fake_token = Some(false);
        security.owner_address = None;
        security.top10_holder_percent = Some(20.0);
        security.creator_percentage = Some(1.0);

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        assert!(result.failed);
        assert!(result.violations.iter().any(|v| v.category == "Platform"));
    }

    #[test]
    fn test_unknown_platform_hard_stop_is_warning_severity() {
        let security = BirdeyeTokenSecurity::default();

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        let platform_violation = result
            .violations
            .iter()
            .find(|v| v.category == "Platform")
            .expect("Platform violation must exist for unknown platform");

        assert_eq!(platform_violation.severity, HardStopSeverity::Warning);
    }

    #[test]
    fn test_known_platform_does_not_trigger_platform_hard_stop() {
        let security = BirdeyeTokenSecurity::default();

        let pumpfun = crate::platform::detect_platform("mintaddresspump", &security);
        let result = check_hard_stops(&security, &pumpfun, None);

        assert!(result.violations.iter().all(|v| v.category != "Platform"));
    }

    #[test]
    fn test_unknown_platform_warning_does_not_cap_score() {
        let mut security = BirdeyeTokenSecurity::default();
        security.non_transferable = Some(false);
        security.fake_token = Some(false);
        security.owner_address = None;
        security.top10_holder_percent = Some(15.0);
        security.creator_percentage = Some(0.5);

        let result = check_hard_stops(&security, &PlatformProfile::unknown(), None);

        assert!(result.failed);
        assert_eq!(result.override_score, None);
    }
}
