import Foundation

public class PrivacyFirewall {
    public static let shared = PrivacyFirewall()
    
    private let cacheLock = NSLock()
    private var excludedAppsCache: Set<String> = []
    private var lastCacheUpdate: TimeInterval = 0
    private var refreshInFlight = false
    private let cacheTTL: TimeInterval = 10.0 // 10 seconds TTL
    
    private init() {
        refreshExcludedAppsCache()
    }
    
    private func refreshExcludedAppsCache() {
        let rows = DatabaseManager.shared.executeQuery(sql: "SELECT id FROM exclusion_list WHERE category = 'app';")
        var apps = Set<String>()
        for row in rows {
            if let id = row["id"] {
                apps.insert(id.lowercased())
            }
        }
        cacheLock.lock()
        self.excludedAppsCache = apps
        self.lastCacheUpdate = Date().timeIntervalSince1970
        self.refreshInFlight = false
        cacheLock.unlock()
    }
    
    private func scheduleRefreshIfNeeded() {
        cacheLock.lock()
        guard !refreshInFlight else {
            cacheLock.unlock()
            return
        }
        refreshInFlight = true
        cacheLock.unlock()
        
        DispatchQueue.global(qos: .utility).async { [weak self] in
            self?.refreshExcludedAppsCache()
        }
    }
    
    public func isAppExcluded(bundleId: String) -> Bool {
        let now = Date().timeIntervalSince1970
        cacheLock.lock()
        let stale = now - lastCacheUpdate > cacheTTL
        let cache = excludedAppsCache
        cacheLock.unlock()
        
        if stale {
            scheduleRefreshIfNeeded()
        }
        return cache.contains(bundleId.lowercased())
    }
    
    // MARK: - Core Validation Middleware
    
    public func isSafeToProcess(text: String, appBundleId: String, fieldType: String? = nil) -> Bool {
        // 1. Is it a password field?
        if let fieldType = fieldType, fieldType.contains("Password") || fieldType.contains("Secure") {
            return false
        }
        
        // 2. Is the application on the exclusion list?
        if isAppExcluded(bundleId: appBundleId) {
            return false
        }
        
        // 3. Contains SSH or Private Keys?
        if text.contains("-----BEGIN") && text.contains("PRIVATE KEY-----") {
            return false
        }
        
        // 4. Scan for AWS credentials, Stripe keys, Slack secrets, or high-entropy tokens
        if hasHighEntropySecrets(text) || isHighEntropyToken(text) {
            return false
        }
        
        // 5. Scan for Credit Cards utilizing Luhn validation
        if containsCreditCard(text) {
            return false
        }
        
        return true
    }
    
    // MARK: - Secret Scanners
    
    private func hasHighEntropySecrets(_ text: String) -> Bool {
        let patterns = [
            "\\bAKIA[0-9A-Z]{16}\\b", // AWS Key ID
            "\\bsk_live_[0-9a-zA-Z]{24}\\b", // Stripe Secret Key
            "\\bxox[baprs]-[0-9a-zA-Z\\-]+\\b", // Slack Tokens
            "mongodb\\+srv:\\/\\/[a-zA-Z0-9_\\-]+:[a-zA-Z0-9_\\-]+@", // Connection strings
            "postgres:\\/\\/[a-zA-Z0-9_\\-]+:[a-zA-Z0-9_\\-]+@"
        ]
        
        for pattern in patterns {
            if let regex = try? NSRegularExpression(pattern: pattern, options: []),
               regex.firstMatch(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count)) != nil {
                return true
            }
        }
        return false
    }
    
    private func containsCreditCard(_ text: String) -> Bool {
        // Find sequences of numbers that look like credit cards (13 to 19 digits)
        // Allowing for spaces or hyphens between groupings
        let pattern = "\\b(?:\\d[\\s-]*){13,19}\\b"
        guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return false }
        
        let nsString = text as NSString
        let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
        
        for match in matches {
            let matchedStr = nsString.substring(with: match.range)
            // Strip out non-digits
            let cleanNumber = matchedStr.filter { $0.isNumber }
            if checkLuhn(cleanNumber) {
                return true
            }
        }
        
        return false
    }
    
    private func checkLuhn(_ number: String) -> Bool {
        let digits = number.compactMap { Int(String($0)) }
        guard digits.count >= 13 && digits.count <= 19 else { return false }
        
        var sum = 0
        let reversed = digits.reversed()
        for (index, digit) in reversed.enumerated() {
            if index % 2 == 1 {
                let doubled = digit * 2
                sum += doubled > 9 ? doubled - 9 : doubled
            } else {
                sum += digit
            }
        }
        return sum % 10 == 0
    }
    
    private func isHighEntropyToken(_ text: String) -> Bool {
        // Find alphanumeric/base64-like words > 20 characters
        let pattern = "\\b[A-Za-z0-9+/=]{20,}\\b"
        guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return false }
        let nsString = text as NSString
        let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
        for match in matches {
            let token = nsString.substring(with: match.range)
            // Verify mixed case and digits to filter out simple long words/spaces
            let hasLower = token.contains { $0.isLowercase }
            let hasUpper = token.contains { $0.isUppercase }
            let hasDigit = token.contains { $0.isNumber }
            if hasLower && hasUpper && hasDigit {
                return true
            }
        }
        return false
    }
}
