<?php
/**
 * OTP Manager Class
 * Handles OTP generation, sending, and verification
 */

class OTPManager {
    private $db;
    private $config;
    
    public function __construct($db) {
        $this->db = $db;
        $this->config = require __DIR__ . '/../config/email_config.php';
        
        // Override config with database settings if available
        $this->loadDatabaseSettings();
    }
    
    /**
     * Load email settings from database
     */
    private function loadDatabaseSettings() {
        try {
            $settings = [
                'email_mode' => 'mode',
                'mail_host' => 'smtp_host',
                'mail_port' => 'smtp_port',
                'mail_encryption' => 'smtp_secure',
                'mail_username' => 'smtp_username',
                'mail_from_email' => 'from_email',
                'mail_from_name' => 'from_name'
            ];
            
            foreach ($settings as $dbKey => $configKey) {
                $setting = $this->db->fetch(
                    'SELECT setting_value FROM admin_settings WHERE setting_key = ?',
                    [$dbKey]
                );
                
                if ($setting && !empty($setting['setting_value'])) {
                    $this->config[$configKey] = $setting['setting_value'];
                }
            }
            
            // Load encrypted password
            $passwordSetting = $this->db->fetch(
                'SELECT setting_value FROM admin_settings WHERE setting_key = ?',
                ['mail_password_encrypted']
            );
            
            if ($passwordSetting && !empty($passwordSetting['setting_value'])) {
                $this->config['smtp_password'] = base64_decode($passwordSetting['setting_value']);
            }
        } catch (Exception $e) {
            error_log('Failed to load email settings from database: ' . $e->getMessage());
        }
    }
    
    /**
     * Generate and send OTP to email
     */
    public function generateAndSendOTP($email, $name = '') {
        try {
            // Generate 6-digit OTP
            $otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
            $expiryTime = date('Y-m-d H:i:s', strtotime('+' . $this->config['otp_expiry_minutes'] . ' minutes'));
            
            // Check if OTP already exists for this email
            $existingOTP = $this->db->fetch(
                'SELECT id FROM email_otps WHERE email = ? AND expires_at > NOW()',
                [$email]
            );
            
            if ($existingOTP) {
                // Delete old OTP
                $this->db->query('DELETE FROM email_otps WHERE email = ?', [$email]);
            }
            
            // Store OTP in database
            $this->db->insert('email_otps', [
                'email' => $email,
                'otp' => $otp,
                'attempts' => 0,
                'created_at' => date('Y-m-d H:i:s'),
                'expires_at' => $expiryTime
            ]);
            
            // Send OTP email
            $this->sendOTPEmail($email, $otp, $name);
            
            return ['success' => true, 'message' => 'OTP sent to ' . $email];
        } catch (Exception $e) {
            error_log('OTP Generation Error: ' . $e->getMessage());
            return ['success' => false, 'message' => 'Failed to send OTP: ' . $e->getMessage()];
        }
    }
    
    /**
     * Send OTP via Email
     */
    private function sendOTPEmail($email, $otp, $name = '') {
        $subject = 'Your OTP Verification Code - ' . APP_NAME;
        
        $emailBody = "
            <html>
                <head>
                    <style>
                        body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f5f5f5; }
                        .container { background: white; max-width: 500px; margin: 30px auto; padding: 40px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
                        .header { text-align: center; margin-bottom: 30px; }
                        .logo { font-size: 24px; font-weight: bold; color: #667eea; }
                        .content { text-align: center; }
                        .otp-box { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px; margin: 20px 0; font-size: 32px; font-weight: bold; letter-spacing: 5px; }
                        .info { color: #666; margin: 15px 0; font-size: 14px; }
                        .warning { background: #fff3cd; color: #856404; padding: 10px; border-radius: 5px; margin: 15px 0; font-size: 13px; }
                        .footer { text-align: center; color: #999; font-size: 12px; margin-top: 30px; border-top: 1px solid #eee; padding-top: 15px; }
                        .footer a { color: #667eea; text-decoration: none; }
                    </style>
                </head>
                <body>
                    <div class='container'>
                        <div class='header'>
                            <div class='logo'>🔐 " . APP_NAME . "</div>
                        </div>
                        
                        <div class='content'>
                            <h2>Email Verification</h2>
                            <p>Hi " . htmlspecialchars($name) . ",</p>
                            <p>Your OTP verification code is:</p>
                            
                            <div class='otp-box'>$otp</div>
                            
                            <div class='info'>
                                <p>This code will expire in " . $this->config['otp_expiry_minutes'] . " minutes</p>
                            </div>
                            
                            <div class='warning'>
                                ⚠️ Never share this code with anyone. We will never ask for your OTP.
                            </div>
                            
                            <p style='color: #666; margin-top: 20px;'>
                                If you didn't request this code, please ignore this email.
                            </p>
                        </div>
                        
                        <div class='footer'>
                            <p>&copy; " . date('Y') . " " . APP_NAME . ". All rights reserved.</p>
                        </div>
                    </div>
                </body>
            </html>
        ";
        
        // Send using PHP mail or SMTP
        return $this->sendEmail($email, $subject, $emailBody);
    }
    
    /**
     * Send email using SMTP or PHP mail() function
     */
    private function sendEmail($to, $subject, $body) {
        if ($this->config['mode'] === 'smtp') {
            return $this->sendViaSMTP($to, $subject, $body);
        } else {
            return $this->sendViaPhpMail($to, $subject, $body);
        }
    }
    
    /**
     * Send email via SMTP (GMAIL compatible)
     */
    private function sendViaSMTP($to, $subject, $body) {
        try {
            $host = $this->config['smtp_host'];
            $port = $this->config['smtp_port'];
            $secure = $this->config['smtp_secure'];
            $username = $this->config['smtp_username'];
            $password = $this->config['smtp_password'];
            $timeout = $this->config['smtp_timeout'] ?? 10;
            
            if (empty($username) || empty($password)) {
                error_log("SMTP credentials not configured. Set MAIL_USERNAME and MAIL_PASSWORD environment variables.");
                return $this->sendViaPhpMail($to, $subject, $body);
            }
            
            // Connect to SMTP server
            $context = stream_context_create([
                'ssl' => [
                    'verify_peer' => false,
                    'verify_peer_name' => false,
                    'allow_self_signed' => true
                ]
            ]);
            
            $protocol = ($secure === 'tls') ? 'tls' : 'ssl';
            $connection = @fsockopen($protocol . '://' . $host, $port, $errno, $errstr, $timeout);
            
            if (!$connection) {
                error_log("SMTP Connection Failed: $errstr ($errno) - Falling back to PHP mail()");
                return $this->sendViaPhpMail($to, $subject, $body);
            }
            
            stream_set_blocking($connection, true);
            stream_set_timeout($connection, $timeout);
            
            // Helper function to read SMTP response (handles multi-line)
            $readResponse = function($fp) {
                $response = '';
                while (!feof($fp)) {
                    $line = fgets($fp, 1024);
                    if ($line === false) break;
                    $response .= $line;
                    // Check if this is the last line (3 digits followed by space)
                    if (preg_match('/^\d{3} /', $line)) break;
                }
                return $response;
            };
            
            // Read server greeting
            $response = $readResponse($connection);
            if (strpos($response, '220') === false) {
                error_log("SMTP Server Error: " . trim($response));
                fclose($connection);
                return false;
            }
            
            // Send EHLO command
            fputs($connection, "EHLO localhost\r\n");
            $response = $readResponse($connection);
            
            // Authenticate
            fputs($connection, "AUTH LOGIN\r\n");
            $response = fgets($connection, 1024);
            if (strpos($response, '334') === false) {
                error_log("AUTH LOGIN not supported: " . trim($response));
                fclose($connection);
                return false;
            }
            
            // Send username
            fputs($connection, base64_encode($username) . "\r\n");
            $response = fgets($connection, 1024);
            if (strpos($response, '334') === false) {
                error_log("Username rejected: " . trim($response));
                fclose($connection);
                return false;
            }
            
            // Send password
            fputs($connection, base64_encode($password) . "\r\n");
            $response = fgets($connection, 1024);
            
            if (strpos($response, '235') === false && strpos($response, '2.7.0') === false) {
                error_log("SMTP Authentication Failed: " . trim($response));
                fclose($connection);
                return false;
            }
            
            // Send FROM
            fputs($connection, "MAIL FROM:<" . $this->config['from_email'] . ">\r\n");
            $response = fgets($connection, 1024);
            
            // Send TO
            fputs($connection, "RCPT TO:<$to>\r\n");
            $response = fgets($connection, 1024);
            
            // Send DATA
            fputs($connection, "DATA\r\n");
            $response = fgets($connection, 1024);
            
            // Compose email
            $headers = "From: " . $this->config['from_name'] . " <" . $this->config['from_email'] . ">\r\n";
            $headers .= "To: $to\r\n";
            $headers .= "Subject: $subject\r\n";
            $headers .= "MIME-Version: 1.0\r\n";
            $headers .= "Content-type: text/html; charset=UTF-8\r\n";
            $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
            
            $message = $headers . "\r\n" . $body;
            
            // Send message
            fputs($connection, $message . "\r\n.\r\n");
            $response = fgets($connection, 1024);
            
            // QUIT
            fputs($connection, "QUIT\r\n");
            fclose($connection);
            
            error_log("Email sent successfully to: $to via SMTP");
            return true;
            
        } catch (Exception $e) {
            error_log("SMTP Error: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Send email using PHP mail() function
     */
    private function sendViaPhpMail($to, $subject, $body) {
        $headers = "MIME-Version: 1.0\r\n";
        $headers .= "Content-type: text/html; charset=UTF-8\r\n";
        $headers .= "From: " . $this->config['from_name'] . " <" . $this->config['from_email'] . ">\r\n";
        $headers .= "Reply-To: " . $this->config['from_email'] . "\r\n";
        $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
        
        // Send email
        $result = @mail($to, $subject, $body, $headers);
        
        error_log("Email sent to: $to via PHP mail() - Result: " . ($result ? "Success" : "Failed"));
        
        return $result;
    }
    
    /**
     * Verify OTP
     */
    public function verifyOTP($email, $otp) {
        try {
            // Check if OTP exists and is valid
            $otpRecord = $this->db->fetch(
                'SELECT id, otp, attempts, expires_at FROM email_otps WHERE email = ?',
                [$email]
            );
            
            if (!$otpRecord) {
                return ['success' => false, 'message' => 'OTP not found. Please request a new one.'];
            }
            
            // Check if OTP has expired
            if (strtotime($otpRecord['expires_at']) < time()) {
                $this->db->query('DELETE FROM email_otps WHERE id = ?', [$otpRecord['id']]);
                return ['success' => false, 'message' => 'OTP has expired. Please request a new one.'];
            }
            
            // Check attempts
            if ($otpRecord['attempts'] >= $this->config['otp_max_attempts']) {
                return ['success' => false, 'message' => 'Too many incorrect attempts. Please request a new OTP.'];
            }
            
            // Verify OTP
            if ($otpRecord['otp'] !== $otp) {
                // Increment attempts
                $this->db->update('email_otps',
                    ['attempts' => $otpRecord['attempts'] + 1],
                    'id = ?',
                    ['id' => $otpRecord['id']]
                );
                return ['success' => false, 'message' => 'Invalid OTP. Please try again.'];
            }
            
            // OTP is correct - delete it
            $this->db->query('DELETE FROM email_otps WHERE id = ?', [$otpRecord['id']]);
            
            return ['success' => true, 'message' => 'OTP verified successfully'];
        } catch (Exception $e) {
            error_log('OTP Verification Error: ' . $e->getMessage());
            return ['success' => false, 'message' => 'Verification failed: ' . $e->getMessage()];
        }
    }
    
    /**
     * Resend OTP
     */
    public function resendOTP($email) {
        try {
            // Delete old OTP
            $this->db->query('DELETE FROM email_otps WHERE email = ?', [$email]);
            
            // Generate new OTP
            $otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
            $expiryTime = date('Y-m-d H:i:s', strtotime('+' . $this->config['otp_expiry_minutes'] . ' minutes'));
            
            // Store new OTP
            $this->db->insert('email_otps', [
                'email' => $email,
                'otp' => $otp,
                'attempts' => 0,
                'created_at' => date('Y-m-d H:i:s'),
                'expires_at' => $expiryTime
            ]);
            
            // Send email
            $this->sendOTPEmail($email, $otp);
            
            return ['success' => true, 'message' => 'New OTP sent to ' . $email];
        } catch (Exception $e) {
            error_log('Resend OTP Error: ' . $e->getMessage());
            return ['success' => false, 'message' => 'Failed to resend OTP'];
        }
    }
    
    /**
     * Get remaining OTP time
     */
    public function getRemainingTime($email) {
        $otpRecord = $this->db->fetch(
            'SELECT expires_at FROM email_otps WHERE email = ? AND expires_at > NOW()',
            [$email]
        );
        
        if (!$otpRecord) {
            return 0;
        }
        
        $remaining = strtotime($otpRecord['expires_at']) - time();
        return max(0, $remaining);
    }
}
?>
