use regex::Regex;
use std::path::Path;
use uuid::Uuid;

use crate::types::{FindingType, Language, Location, Severity, Vulnerability, VulnerabilityType};

/// Category of a crypto library
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LibraryCategory {
    /// Library is purely for quantum-vulnerable operations (e.g., rsa, ecdsa)
    PureVulnerable,
    /// Library contains both safe and vulnerable algorithms (e.g., cryptography, OpenSSL)
    MixedPurpose,
}

/// A known cryptographic library
pub struct CryptoLibrary {
    pub name: &'static str,
    pub category: LibraryCategory,
    pub import_patterns: Vec<&'static str>,
    pub languages: Vec<Language>,
    pub description: &'static str,
    pub recommendation: &'static str,
}

/// Library detector for identifying crypto library imports
pub struct LibraryDetector {
    libraries: Vec<CryptoLibrary>,
    compiled_patterns: Vec<(Regex, CryptoLibrary)>,
}

impl LibraryDetector {
    pub fn new() -> Self {
        let libraries = Self::get_known_libraries();
        let mut compiled_patterns = Vec::new();
        
        for lib in &libraries {
            for pattern in &lib.import_patterns {
                if let Ok(regex) = Regex::new(pattern) {
                    compiled_patterns.push((regex, CryptoLibrary {
                        name: lib.name,
                        category: lib.category,
                        import_patterns: lib.import_patterns.clone(),
                        languages: lib.languages.clone(),
                        description: lib.description,
                        recommendation: lib.recommendation,
                    }));
                }
            }
        }
        
        Self {
            libraries,
            compiled_patterns,
        }
    }
    
    /// Get all known crypto libraries
    fn get_known_libraries() -> Vec<CryptoLibrary> {
        vec![
            // ========== PURE VULNERABLE LIBRARIES ==========
            // Python
            CryptoLibrary {
                name: "rsa",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r"(?m)^\s*import\s+rsa\b",
                    r"(?m)^\s*from\s+rsa\s+import",
                ],
                languages: vec![Language::Python],
                description: "Python RSA library - purely quantum-vulnerable",
                recommendation: "Migrate to liboqs-python or pqcrypto for post-quantum cryptography",
            },
            CryptoLibrary {
                name: "ecdsa",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r"(?m)^\s*import\s+ecdsa\b",
                    r"(?m)^\s*from\s+ecdsa\s+import",
                ],
                languages: vec![Language::Python],
                description: "Python ECDSA library - purely quantum-vulnerable",
                recommendation: "Migrate to Dilithium or SPHINCS+ for signatures",
            },
            CryptoLibrary {
                name: "dsa",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r"(?i)from\s+Crypto\.PublicKey\s+import\s+DSA",
                    r"(?i)from\s+cryptography\.hazmat\.primitives\.asymmetric\s+import\s+dsa",
                ],
                languages: vec![Language::Python],
                description: "Python DSA library - purely quantum-vulnerable",
                recommendation: "Migrate to Dilithium for signatures",
            },
            // JavaScript/TypeScript
            CryptoLibrary {
                name: "node-rsa",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r#"require\s*\(\s*['"]node-rsa['"]\s*\)"#,
                    r#"from\s+['"]node-rsa['"]\s*"#,
                    r#"import\s+.*\s+from\s+['"]node-rsa['"]"#,
                ],
                languages: vec![Language::JavaScript, Language::TypeScript],
                description: "Node.js RSA library - purely quantum-vulnerable",
                recommendation: "Migrate to liboqs-node for post-quantum cryptography",
            },
            CryptoLibrary {
                name: "elliptic",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r#"require\s*\(\s*['"]elliptic['"]\s*\)"#,
                    r#"from\s+['"]elliptic['"]\s*"#,
                    r#"import\s+.*\s+from\s+['"]elliptic['"]"#,
                ],
                languages: vec![Language::JavaScript, Language::TypeScript],
                description: "Elliptic curve library - purely quantum-vulnerable",
                recommendation: "Migrate to post-quantum signature schemes",
            },
            CryptoLibrary {
                name: "jsrsasign",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r#"require\s*\(\s*['"]jsrsasign['"]\s*\)"#,
                    r#"from\s+['"]jsrsasign['"]\s*"#,
                    r#"import\s+.*\s+from\s+['"]jsrsasign['"]"#,
                ],
                languages: vec![Language::JavaScript, Language::TypeScript],
                description: "RSA/ECDSA signing library - purely quantum-vulnerable",
                recommendation: "Migrate to post-quantum cryptography",
            },
            CryptoLibrary {
                name: "secp256k1",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r#"require\s*\(\s*['"]secp256k1['"]\s*\)"#,
                    r#"from\s+['"]secp256k1['"]\s*"#,
                    r#"import\s+.*\s+from\s+['"]secp256k1['"]"#,
                ],
                languages: vec![Language::JavaScript, Language::TypeScript],
                description: "Bitcoin secp256k1 curve - purely quantum-vulnerable",
                recommendation: "Monitor blockchain PQC developments",
            },
            // Rust
            CryptoLibrary {
                name: "rsa (crate)",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r"use\s+rsa::",
                    r"extern\s+crate\s+rsa\b",
                ],
                languages: vec![Language::Rust],
                description: "Rust RSA crate - purely quantum-vulnerable",
                recommendation: "Migrate to pqcrypto crate for post-quantum",
            },
            CryptoLibrary {
                name: "ecdsa (crate)",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r"use\s+ecdsa::",
                    r"extern\s+crate\s+ecdsa\b",
                ],
                languages: vec![Language::Rust],
                description: "Rust ECDSA crate - purely quantum-vulnerable",
                recommendation: "Migrate to pqcrypto crate for post-quantum",
            },
            CryptoLibrary {
                name: "p256/p384/p521",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r"use\s+p256::",
                    r"use\s+p384::",
                    r"use\s+p521::",
                ],
                languages: vec![Language::Rust],
                description: "Rust NIST curve crates - purely quantum-vulnerable",
                recommendation: "Migrate to pqcrypto crate for post-quantum",
            },
            CryptoLibrary {
                name: "ed25519",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r"use\s+ed25519::",
                    r"use\s+ed25519_dalek::",
                ],
                languages: vec![Language::Rust],
                description: "Rust Ed25519 crate - purely quantum-vulnerable",
                recommendation: "Migrate to Dilithium for signatures",
            },
            // Go
            CryptoLibrary {
                name: "crypto/rsa",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r#"import\s+.*"crypto/rsa""#,
                    r#""crypto/rsa""#,
                ],
                languages: vec![Language::Go],
                description: "Go crypto/rsa package - purely quantum-vulnerable",
                recommendation: "Migrate to circl or go-pqc for post-quantum",
            },
            CryptoLibrary {
                name: "crypto/ecdsa",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r#"import\s+.*"crypto/ecdsa""#,
                    r#""crypto/ecdsa""#,
                ],
                languages: vec![Language::Go],
                description: "Go crypto/ecdsa package - purely quantum-vulnerable",
                recommendation: "Migrate to circl for post-quantum signatures",
            },
            CryptoLibrary {
                name: "crypto/dsa",
                category: LibraryCategory::PureVulnerable,
                import_patterns: vec![
                    r#"import\s+.*"crypto/dsa""#,
                    r#""crypto/dsa""#,
                ],
                languages: vec![Language::Go],
                description: "Go crypto/dsa package - purely quantum-vulnerable",
                recommendation: "Migrate to Dilithium for signatures",
            },
            
            // ========== MIXED PURPOSE LIBRARIES ==========
            // Python
            CryptoLibrary {
                name: "cryptography",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r"(?m)^\s*import\s+cryptography\b",
                    r"(?m)^\s*from\s+cryptography\s+import",
                    r"from\s+cryptography\.hazmat",
                ],
                languages: vec![Language::Python],
                description: "Python cryptography library - contains both safe and vulnerable algorithms",
                recommendation: "Audit usage for RSA/ECDSA/DH. Use AES-256-GCM and SHA-256+ for quantum safety",
            },
            CryptoLibrary {
                name: "PyCrypto/PyCryptodome",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r"(?i)from\s+Crypto\s+import",
                    r"(?i)from\s+Crypto\.",
                    r"(?i)from\s+Cryptodome\s+import",
                    r"(?i)from\s+Cryptodome\.",
                ],
                languages: vec![Language::Python],
                description: "PyCrypto/PyCryptodome - contains both safe and vulnerable algorithms",
                recommendation: "Audit for RSA/DSA/ECDSA usage. Prefer AES and SHA-256+",
            },
            CryptoLibrary {
                name: "paramiko",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r"(?m)^\s*import\s+paramiko\b",
                    r"(?m)^\s*from\s+paramiko\s+import",
                ],
                languages: vec![Language::Python],
                description: "Python SSH library - uses RSA/ECDSA for key exchange",
                recommendation: "Monitor for PQ-SSH support when available",
            },
            // JavaScript/TypeScript
            CryptoLibrary {
                name: "node-forge",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r#"require\s*\(\s*['"]node-forge['"]\s*\)"#,
                    r#"from\s+['"]node-forge['"]\s*"#,
                    r#"import\s+.*\s+from\s+['"]node-forge['"]"#,
                ],
                languages: vec![Language::JavaScript, Language::TypeScript],
                description: "Node-forge library - contains both safe and vulnerable algorithms",
                recommendation: "Audit for RSA/ECDSA usage. Use AES and SHA-256+ for quantum safety",
            },
            CryptoLibrary {
                name: "crypto-js",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r#"require\s*\(\s*['"]crypto-js['"]\s*\)"#,
                    r#"from\s+['"]crypto-js['"]\s*"#,
                    r#"import\s+.*\s+from\s+['"]crypto-js['"]"#,
                ],
                languages: vec![Language::JavaScript, Language::TypeScript],
                description: "CryptoJS library - mostly symmetric but check algorithm usage",
                recommendation: "Verify using AES and not DES/3DES. Avoid if used with RSA",
            },
            CryptoLibrary {
                name: "jsonwebtoken",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r#"require\s*\(\s*['"]jsonwebtoken['"]\s*\)"#,
                    r#"from\s+['"]jsonwebtoken['"]\s*"#,
                    r#"import\s+.*\s+from\s+['"]jsonwebtoken['"]"#,
                ],
                languages: vec![Language::JavaScript, Language::TypeScript],
                description: "JWT library - often uses RS256/ES256 (quantum-vulnerable)",
                recommendation: "If using RS256/ES256, plan migration. HS256/HS512 are quantum-safe",
            },
            CryptoLibrary {
                name: "jose",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r#"require\s*\(\s*['"]jose['"]\s*\)"#,
                    r#"from\s+['"]jose['"]\s*"#,
                    r#"import\s+.*\s+from\s+['"]jose['"]"#,
                ],
                languages: vec![Language::JavaScript, Language::TypeScript],
                description: "JOSE library - JWT/JWE/JWK often uses RSA/ECDSA",
                recommendation: "Audit JWT signing algorithm. Use HS256/HS512 for quantum safety",
            },
            // Java
            CryptoLibrary {
                name: "BouncyCastle",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r"import\s+org\.bouncycastle\.",
                    r"import\s+.*bcprov",
                    r"import\s+.*bcpkix",
                ],
                languages: vec![Language::Java, Language::Kotlin, Language::Scala, Language::Groovy],
                description: "BouncyCastle - comprehensive crypto library with PQC support in newer versions",
                recommendation: "Use BC's PQC providers (bcpqc-jdk18on) for post-quantum algorithms",
            },
            // C/C++
            CryptoLibrary {
                name: "OpenSSL",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r#"#include\s*<openssl/"#,
                    r#"#include\s*"openssl/"#,
                ],
                languages: vec![Language::C, Language::Cpp],
                description: "OpenSSL - contains both safe and vulnerable algorithms",
                recommendation: "Use OpenSSL 3.2+ with oqsprovider for PQC. Audit RSA/ECDSA usage",
            },
            // Rust
            CryptoLibrary {
                name: "ring",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r"use\s+ring::",
                    r"extern\s+crate\s+ring\b",
                ],
                languages: vec![Language::Rust],
                description: "Ring crypto library - contains RSA/ECDSA",
                recommendation: "Audit for RSA/ECDSA. Use pqcrypto crate for post-quantum",
            },
            CryptoLibrary {
                name: "openssl (crate)",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r"use\s+openssl::",
                    r"extern\s+crate\s+openssl\b",
                ],
                languages: vec![Language::Rust],
                description: "Rust OpenSSL bindings - contains both safe and vulnerable algorithms",
                recommendation: "Audit for RSA/ECDSA. Use pqcrypto crate for post-quantum",
            },
            // Go
            CryptoLibrary {
                name: "crypto/tls",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r#"import\s+.*"crypto/tls""#,
                    r#""crypto/tls""#,
                ],
                languages: vec![Language::Go],
                description: "Go TLS package - uses RSA/ECDSA for certificates",
                recommendation: "Monitor for PQ-TLS support in Go",
            },
            CryptoLibrary {
                name: "crypto/x509",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r#"import\s+.*"crypto/x509""#,
                    r#""crypto/x509""#,
                ],
                languages: vec![Language::Go],
                description: "Go X.509 package - certificates typically use RSA/ECDSA",
                recommendation: "Monitor for PQ certificate support",
            },
            // PHP
            CryptoLibrary {
                name: "openssl (PHP)",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r"openssl_pkey_new",
                    r"openssl_sign",
                    r"openssl_verify",
                    r"openssl_public_encrypt",
                ],
                languages: vec![Language::Php],
                description: "PHP OpenSSL extension - contains both safe and vulnerable algorithms",
                recommendation: "Audit for RSA/ECDSA usage. Use sodium for symmetric crypto",
            },
            // Ruby
            CryptoLibrary {
                name: "OpenSSL (Ruby)",
                category: LibraryCategory::MixedPurpose,
                import_patterns: vec![
                    r#"require\s+['"]openssl['"]"#,
                    r"OpenSSL::PKey",
                ],
                languages: vec![Language::Ruby],
                description: "Ruby OpenSSL bindings - contains both safe and vulnerable algorithms",
                recommendation: "Audit for RSA/ECDSA usage",
            },
        ]
    }
    
    /// Detect library imports in source code
    pub fn detect_imports(
        &self,
        source: &str,
        file_path: &Path,
        language: Language,
    ) -> Vec<Vulnerability> {
        let mut vulnerabilities = Vec::new();
        
        for (regex, lib) in &self.compiled_patterns {
            // Check if language matches
            if !lib.languages.contains(&language) && !lib.languages.is_empty() {
                continue;
            }
            
            for mat in regex.find_iter(source) {
                let (line, column) = self.offset_to_position(source, mat.start());
                
                let (severity, finding_type, vuln_type) = match lib.category {
                    LibraryCategory::PureVulnerable => (
                        Severity::High,
                        FindingType::VulnerableImport,
                        VulnerabilityType::VulnerableLibrary,
                    ),
                    LibraryCategory::MixedPurpose => (
                        Severity::Low,
                        FindingType::AuditRequired,
                        VulnerabilityType::VulnerableLibraryMixed,
                    ),
                };
                
                vulnerabilities.push(Vulnerability {
                    id: Uuid::new_v4(),
                    vuln_type,
                    severity,
                    location: Location {
                        file: file_path.to_path_buf(),
                        line,
                        column,
                        end_line: None,
                        end_column: None,
                    },
                    description: lib.description.to_string(),
                    code_snippet: self.extract_snippet(source, line),
                    recommendation: lib.recommendation.to_string(),
                    migration_impacts: vec![],
                    cwe_id: Some("CWE-327".to_string()),
                    is_dependency: true,
                    dependency_chain: None,
                    finding_type,
                    library_name: Some(lib.name.to_string()),
                });
            }
        }
        
        vulnerabilities
    }
    
    fn offset_to_position(&self, source: &str, offset: usize) -> (usize, usize) {
        let mut line = 1;
        let mut col = 1;
        
        for (i, c) in source.chars().enumerate() {
            if i >= offset {
                break;
            }
            if c == '\n' {
                line += 1;
                col = 1;
            } else {
                col += 1;
            }
        }
        
        (line, col)
    }
    
    fn extract_snippet(&self, source: &str, line: usize) -> Option<String> {
        source.lines().nth(line.saturating_sub(1)).map(|s| s.trim().to_string())
    }
}

impl Default for LibraryDetector {
    fn default() -> Self {
        Self::new()
    }
}
