<?php

namespace App\classes;

use App\classes\Database;

class PasswordResetSecurity
{
    private $conn;
    
    public function __construct($connection = null)
    {
        $this->conn = $connection ?: Database::db();
    }
    
    /**
     * Generate a secure OTP code
     */
    public function generateOTP(): string
    {
        return str_pad(random_int(100000, 999999), 6, '0', STR_PAD_LEFT);
    }
    
    /**
     * Generate a secure token
     */
    public function generateToken(): string
    {
        return bin2hex(random_bytes(32));
    }
    
    /**
     * Hash a token for storage
     */
    public function hashToken(string $token): string
    {
        return password_hash($token, PASSWORD_DEFAULT);
    }
    
    /**
     * Verify a token
     */
    public function verifyToken(string $token, string $hash): bool
    {
        return password_verify($token, $hash);
    }
    
    /**
     * Check if user has too many recent reset attempts
     */
    public function checkRateLimit(string $email, int $maxAttempts = 3, int $timeWindow = 3600): bool
    {
        $stmt = $this->conn->prepare("
            SELECT COUNT(*) as attempt_count 
            FROM password_reset_tokens 
            WHERE email = ? AND created_at > DATE_SUB(NOW(), INTERVAL ? SECOND)
        ");
        $stmt->bind_param("si", $email, $timeWindow);
        $stmt->execute();
        $result = $stmt->get_result();
        $data = $result->fetch_assoc();
        $stmt->close();
        
        return $data['attempt_count'] < $maxAttempts;
    }
    
    /**
     * Log security event
     */
    public function logSecurityEvent(string $event, string $email, string $ipAddress, string $userAgent, array $details = []): void
    {
        $logData = [
            'timestamp' => date('Y-m-d H:i:s'),
            'event' => $event,
            'email' => $email,
            'ip_address' => $ipAddress,
            'user_agent' => $userAgent,
            'details' => $details
        ];
        
        $logMessage = json_encode($logData) . "\n";
        file_put_contents('logs/security_events.log', $logMessage, FILE_APPEND | LOCK_EX);
    }
    
    /**
     * Check for suspicious activity
     */
    public function checkSuspiciousActivity(string $email, string $ipAddress): array
    {
        $suspiciousEvents = [];
        
        // Check for multiple failed attempts from same IP
        $stmt = $this->conn->prepare("
            SELECT COUNT(*) as failed_count 
            FROM password_reset_tokens 
            WHERE ip_address = ? AND attempts >= max_attempts AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)
        ");
        $stmt->bind_param("s", $ipAddress);
        $stmt->execute();
        $result = $stmt->get_result();
        $data = $result->fetch_assoc();
        $stmt->close();
        
        if ($data['failed_count'] > 5) {
            $suspiciousEvents[] = 'Multiple failed attempts from same IP';
        }
        
        // Check for rapid successive requests
        $stmt = $this->conn->prepare("
            SELECT COUNT(*) as rapid_count 
            FROM password_reset_tokens 
            WHERE email = ? AND created_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)
        ");
        $stmt->bind_param("s", $email);
        $stmt->execute();
        $result = $stmt->get_result();
        $data = $result->fetch_assoc();
        $stmt->close();
        
        if ($data['rapid_count'] > 3) {
            $suspiciousEvents[] = 'Rapid successive requests';
        }
        
        return $suspiciousEvents;
    }
    
    /**
     * Clean up expired and invalid tokens
     */
    public function cleanupTokens(): array
    {
        $cleanupStats = [
            'expired' => 0,
            'used' => 0,
            'max_attempts' => 0,
            'total' => 0
        ];
        
        try {
            // Clean expired tokens
            $expiredQuery = "DELETE FROM password_reset_tokens WHERE expires_at < NOW()";
            $result = mysqli_query($this->conn, $expiredQuery);
            if ($result) {
                $cleanupStats['expired'] = mysqli_affected_rows($this->conn);
            }
            
            // Clean used tokens older than 1 hour
            $usedQuery = "DELETE FROM password_reset_tokens WHERE used_at IS NOT NULL AND created_at < DATE_SUB(NOW(), INTERVAL 1 HOUR)";
            $result = mysqli_query($this->conn, $usedQuery);
            if ($result) {
                $cleanupStats['used'] = mysqli_affected_rows($this->conn);
            }
            
            // Clean tokens with max attempts
            $maxAttemptsQuery = "DELETE FROM password_reset_tokens WHERE attempts >= max_attempts";
            $result = mysqli_query($this->conn, $maxAttemptsQuery);
            if ($result) {
                $cleanupStats['max_attempts'] = mysqli_affected_rows($this->conn);
            }
            
            $cleanupStats['total'] = $cleanupStats['expired'] + $cleanupStats['used'] + $cleanupStats['max_attempts'];
            
        } catch (Exception $e) {
            error_log("Token cleanup failed: " . $e->getMessage());
        }
        
        return $cleanupStats;
    }
    
    /**
     * Get security statistics
     */
    public function getSecurityStats(): array
    {
        $stats = [];
        
        // Total tokens
        $result = mysqli_query($this->conn, "SELECT COUNT(*) as total FROM password_reset_tokens");
        $data = mysqli_fetch_assoc($result);
        $stats['total_tokens'] = $data['total'];
        
        // Active tokens
        $result = mysqli_query($this->conn, "SELECT COUNT(*) as active FROM password_reset_tokens WHERE expires_at > NOW() AND used_at IS NULL");
        $data = mysqli_fetch_assoc($result);
        $stats['active_tokens'] = $data['active'];
        
        // Failed attempts in last 24 hours
        $result = mysqli_query($this->conn, "SELECT COUNT(*) as failed FROM password_reset_tokens WHERE attempts >= max_attempts AND created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)");
        $data = mysqli_fetch_assoc($result);
        $stats['failed_attempts_24h'] = $data['failed'];
        
        // Unique IPs in last 24 hours
        $result = mysqli_query($this->conn, "SELECT COUNT(DISTINCT ip_address) as unique_ips FROM password_reset_tokens WHERE created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)");
        $data = mysqli_fetch_assoc($result);
        $stats['unique_ips_24h'] = $data['unique_ips'];
        
        return $stats;
    }
    
    /**
     * Validate password strength
     */
    public function validatePasswordStrength(string $password): array
    {
        $errors = [];
        $strength = 0;
        
        if (strlen($password) < 8) {
            $errors[] = "Password must be at least 8 characters long";
        } else {
            $strength++;
        }
        
        if (!preg_match('/[a-z]/', $password)) {
            $errors[] = "Password must contain at least one lowercase letter";
        } else {
            $strength++;
        }
        
        if (!preg_match('/[A-Z]/', $password)) {
            $errors[] = "Password must contain at least one uppercase letter";
        } else {
            $strength++;
        }
        
        if (!preg_match('/\d/', $password)) {
            $errors[] = "Password must contain at least one number";
        } else {
            $strength++;
        }
        
        if (!preg_match('/[^A-Za-z0-9]/', $password)) {
            $errors[] = "Password must contain at least one special character";
        } else {
            $strength++;
        }
        
        return [
            'valid' => empty($errors),
            'errors' => $errors,
            'strength' => $strength,
            'strength_level' => $this->getStrengthLevel($strength)
        ];
    }
    
    /**
     * Get password strength level
     */
    private function getStrengthLevel(int $strength): string
    {
        if ($strength < 2) return 'Very Weak';
        if ($strength < 3) return 'Weak';
        if ($strength < 4) return 'Fair';
        if ($strength < 5) return 'Good';
        return 'Strong';
    }
    
    /**
     * Check if email is valid and not disposable
     */
    public function validateEmail(string $email): array
    {
        $errors = [];
        
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $errors[] = "Invalid email format";
        }
        
        // Check for common disposable email domains
        $disposableDomains = [
            '10minutemail.com', 'tempmail.org', 'guerrillamail.com', 
            'mailinator.com', 'throwaway.email', 'temp-mail.org'
        ];
        
        $domain = substr(strrchr($email, "@"), 1);
        if (in_array(strtolower($domain), $disposableDomains)) {
            $errors[] = "Disposable email addresses are not allowed";
        }
        
        return [
            'valid' => empty($errors),
            'errors' => $errors
        ];
    }
}
?>
