<?php
// login.php - MEMBER LOGIN API INTEGRATED WITH EXISTING AUTH FUNCTIONS

// ============================================
// INITIALIZATION
// ============================================

// Load CORS configuration FIRST
require_once __DIR__ . '/includes/cors.php';
configureCors();

// Load environment variables
require_once __DIR__ . '/includes/config_loader.php';

// Load dependencies
require_once __DIR__ . '/includes/config.php';
require_once __DIR__ . '/includes/auth_functions.php'; // Your existing auth functions
require_once __DIR__ . '/includes/sms_helper.php';
require_once __DIR__ . '/includes/email_helper.php'; // If you have separate email helper
require_once __DIR__ . '/auth/AuditLogger.php';
require_once __DIR__ . '/auth/JWTManager.php';

// Set response headers
header('Content-Type: application/json');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
ini_set('display_errors', 0);
ini_set('log_errors', 1);
error_reporting(E_ALL & ~E_NOTICE);
// Add security headers
header('X-Frame-Options: DENY');
header('X-Content-Type-Options: nosniff');
header('X-XSS-Protection: 1; mode=block');
header('Referrer-Policy: strict-origin-when-cross-origin');

// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    header('Access-Control-Max-Age: 86400');
    header('Content-Length: 0');
    http_response_code(200);
    exit();
}

// Start session using your existing session configuration
if (session_status() === PHP_SESSION_NONE) {
    // Optional: Define your custom session name
    $customSessionName = 'MEMBER_PORTAL_SESSION';

    // Check if a session cookie already exists
    $hasCustomSession = isset($_COOKIE[$customSessionName]);
    $hasDefaultSession = isset($_COOKIE[session_name()]); // usually PHPSESSID

    // --- Decide which session name to use ---
    if ($hasCustomSession) {
        // Resume existing MEMBER_PORTAL_SESSION
        session_name($customSessionName);
    } elseif ($hasDefaultSession) {
        // Stick to the existing PHPSESSID
        // (no change needed)
    } else {
        // Optional: Use custom session for new logins
        session_name($customSessionName);
    }

    // --- Secure session configuration ---
    ini_set('session.cookie_secure', 1);
    ini_set('session.cookie_httponly', 1);
    ini_set('session.use_strict_mode', 1);
    ini_set('session.cookie_samesite', 'Lax');
    ini_set('session.use_only_cookies', 1);
    ini_set('session.gc_maxlifetime', 1800); // 30 mins

    // --- Start session ---
    if (ob_get_level()) ob_clean();
    session_start();

    // --- Optional debug ---
    error_log("Session started → name: " . session_name() . " | ID: " . session_id());
}

// Add request deduplication
$requestId = uniqid('req_', true);
error_log("[$requestId] === LOGIN REQUEST START ===");

// Initialize session tracking
if (!isset($_SESSION['session_id'])) {
    $_SESSION['session_id'] = session_id();
}
if (!isset($_SESSION['last_activity'])) {
    $_SESSION['last_activity'] = time();
}
if (!isset($_SESSION['ip_address'])) {
    $_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'];
}

// Add request deduplication check
$dedupeKey = 'last_login_request_' . session_id();
if (isset($_SESSION[$dedupeKey]) && (time() - $_SESSION[$dedupeKey]) < 2) {
    error_log("[$requestId] Duplicate request detected");
    http_response_code(429);
    echo json_encode(['error' => 'Please wait before trying again.']);
    exit;
}
$_SESSION[$dedupeKey] = time();

// Initialize Audit Logger
try {
    $auditLogger = new AuditLogger($pdo, null, 'LoginSystem');
} catch (Exception $e) {
    error_log("[$requestId] Audit Logger initialization failed: " . $e->getMessage());
    $auditLogger = null;
}

// Initialize JWT Manager
$jwtManager = null;
try {
    $jwtSecretKey = getenv('JWT_SECRET_KEY');
    if (!empty($jwtSecretKey) && strlen($jwtSecretKey) >= 32) {
        $jwtManager = new JWTManager($pdo);
    }
} catch (Exception $e) {
    error_log("[$requestId] JWT Manager initialization failed: " . $e->getMessage());
}

// ============================================
// HELPER FUNCTIONS (NEW OR MODIFIED)
// ============================================

function sendResponse($data, $statusCode = 200) {
    http_response_code($statusCode);
    echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    exit();
}

function getJsonInput() {
    $input = json_decode(file_get_contents('php://input'), true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        return null;
    }
    return $input;
}

function checkIpRateLimit($ip, $pdo, $requestId) {
    try {
        $pdo->prepare("DELETE FROM login_attempts WHERE attempted_at < (NOW() - INTERVAL 10 MINUTE)")->execute();
        
        $stmt = $pdo->prepare("
            SELECT COUNT(*) FROM login_attempts 
            WHERE ip_address = ? 
            AND attempted_at > (NOW() - INTERVAL 10 MINUTE)
        ");
        $stmt->execute([$ip]);
        return (int)$stmt->fetchColumn();
    } catch (Exception $e) {
        error_log("[$requestId] IP rate limit check failed: " . $e->getMessage());
        return 0;
    }
}

function getCsrfToken() {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        $_SESSION['csrf_token_time'] = time();
        error_log("DEBUG: New CSRF token generated: " . $_SESSION['csrf_token']);
    } else {
        error_log("DEBUG: Existing CSRF token: " . $_SESSION['csrf_token']);
    }
    return $_SESSION['csrf_token'];
}

function validateCsrfToken($token) {
    if (empty($token) || empty($_SESSION['csrf_token'])) {
        return false;
    }
    
    if (!hash_equals($_SESSION['csrf_token'], $token)) {
        return false;
    }
    
    $tokenAge = time() - ($_SESSION['csrf_token_time'] ?? 0);
    if ($tokenAge > 86400) {
        unset($_SESSION['csrf_token']);
        return false;
    }
    
    return true;
}

function validateLoginIdentifier($login) {
    $login = trim($login);
    
    if (empty($login)) {
        return ['type' => 'invalid', 'valid' => false];
    }
    
    // Check email
    if (filter_var($login, FILTER_VALIDATE_EMAIL)) {
        return ['type' => 'email', 'valid' => true];
    }
    
    // Check phone number
    $normalizedPhone = normalizePhoneNumber($login);
    if ($normalizedPhone && validateKenyanPhoneNumber($normalizedPhone)) {
        return ['type' => 'phone', 'valid' => true, 'normalized' => $normalizedPhone];
    }
    
    // Check ID number (Kenyan 8-digit)
    if (preg_match('/^\d{8}$/', $login)) {
        return ['type' => 'id_number', 'valid' => true];
    }
    
    // Check username
    if (preg_match('/^[a-zA-Z0-9._-]{3,50}$/', $login)) {
        return ['type' => 'username', 'valid' => true];
    }
    
    return ['type' => 'invalid', 'valid' => false];
}

function normalizePhoneNumber($phone) {
    if (empty($phone)) return '';
    
    $digits = preg_replace('/[^0-9]/', '', $phone);
    
    // Remove leading zeros
    $digits = ltrim($digits, '0');
    
    // Already in 254 format (12 digits)
    if (strlen($digits) === 12 && substr($digits, 0, 3) === '254') {
        return $digits;
    }
    
    // Convert from 10-digit (07xxxxxxxx)
    if (strlen($digits) === 10 && substr($digits, 0, 1) === '7') {
        return '254' . substr($digits, 1);
    }
    
    // Convert from 9-digit (7xxxxxxxx)
    if (strlen($digits) === 9 && substr($digits, 0, 1) === '7') {
        return '254' . $digits;
    }
    
    // Airtel numbers (1xxxxxxxx)
    if (strlen($digits) === 9 && substr($digits, 0, 1) === '1') {
        return '254' . $digits;
    }
    
    return $digits;
}

function validateKenyanPhoneNumber($phone) {
    $phone = preg_replace('/[^0-9]/', '', $phone);
    
    // Must be 12 digits starting with 254
    if (strlen($phone) !== 12 || substr($phone, 0, 3) !== '254') {
        return false;
    }
    
    $mobilePart = substr($phone, 3);
    
    // Check Kenyan mobile prefixes
    $validPrefixes = [
        '70', '71', '72', '74', '75', '76', '77', '78', '79', // Safaricom
        '10', '11' // Airtel
    ];
    
    $prefix = substr($mobilePart, 0, 2);
    return in_array($prefix, $validPrefixes) && strlen($mobilePart) === 9;
}

function completeLogin(
    array $account,
    array $member,
    ?AuditLogger $auditLogger,
    ?JWTManager $jwtManager,
    string $loginMethod,
    bool $rememberMe,
    string $authType,
    string $deviceId = '',
    string $requestId = ''
) {
    global $pdo;

    if (!isset($account['member_id']) || empty($account['member_id'])) {
        error_log("[$requestId] ERROR: Missing member_id");
        throw new Exception('Missing member_id');
    }

    /* ===============================
     * SESSION SETUP
     * =============================== */
    if ($authType === 'session' || $authType === 'hybrid') {
        session_regenerate_id(true);
        error_log("[$requestId] SESSION REGENERATED: New session ID: " . session_id());

        $newSessionData = [
            'member_id'         => $account['member_id'],
            'username'          => $account['username'],
            'email'             => $account['email'],
            'first_name'        => $member['first_name'],
            'last_name'         => $member['last_name'],
            'phone'             => $member['phone_number'],
            'id_number'         => $member['id_number'],
            'authenticated'     => true,
            'auth_type'         => $authType,
            'login_time'        => time(),
            'last_activity'     => time(),
            'ip_address'        => $_SERVER['REMOTE_ADDR'],
            'user_agent_hash'   => hash('sha256', $_SERVER['HTTP_USER_AGENT'] ?? ''),
            'session_id'        => session_id(),
            'kyc_verified'      => $member['kyc_verified'],
            'preference'        => $member['communication_preference'] ?? 'email'
        ];
        
        foreach ($newSessionData as $key => $value) {
            $_SESSION[$key] = $value;
        }
        
        error_log("[$requestId] SESSION UPDATED: Member ID " . $account['member_id'] . " logged in");
    }

    /* ===============================
     * JWT TOKENS (OPTIONAL)
     * =============================== */
    $tokens = null;

    if (($authType === 'jwt' || $authType === 'hybrid') && $jwtManager) {
        try {
            $jwtPayload = [
                'mid'   => $account['member_id'],
                'sid'   => session_id() ?: null,
                'did'   => $deviceId ?: hash('sha256', ($_SERVER['HTTP_USER_AGENT'] ?? '') . $_SERVER['REMOTE_ADDR']),
                'iat'   => time(),
                'atype' => $authType,
                'role'  => 'member'
            ];

            $accessToken = $jwtManager->generateAccessToken($jwtPayload);
            $refreshToken = $jwtManager->generateRefreshToken($account['member_id'], $deviceId, 'member');

            $jwtManager->storeAccessToken(
                $account['member_id'],
                $accessToken,
                hash('sha256', ($_SERVER['HTTP_USER_AGENT'] ?? '') . $_SERVER['REMOTE_ADDR']),
                'member'
            );

            if ($rememberMe) {
                setcookie(
                    'refresh_token',
                    $refreshToken,
                    [
                        'expires'  => time() + $jwtManager->getRefreshTokenExpiry(),
                        'path'     => '/',
                        'secure'   => true,
                        'httponly' => true,
                        'samesite' => 'Strict'
                    ]
                );
            }

            $tokens = [
                'access_token'  => $accessToken,
                'refresh_token' => $rememberMe ? null : $refreshToken,
                'token_type'    => 'Bearer',
                'expires_in'    => $jwtManager->getAccessTokenExpiry()
            ];
            
        } catch (Exception $e) {
            error_log("[$requestId] ERROR generating JWT tokens: " . $e->getMessage());
        }
    }

    /* ===============================
     * AUDIT LOG
     * =============================== */
    if ($auditLogger) {
        try {
            $auditLogger->log($account['member_id'], 'login_successful', [
                'auth_type'    => $authType,
                'session_id'   => session_id() ?: null,
                'device_id'    => $deviceId,
                'ip'           => $_SERVER['REMOTE_ADDR'],
                'request_id'   => $requestId,
                'login_method' => $loginMethod,
                'user_type'    => 'member'
            ]);
        } catch (Exception $e) {
            error_log("[$requestId] ERROR logging audit: " . $e->getMessage());
        }
    }

    /* ===============================
     * CHECK 2FA STATUS
     * =============================== */
    $requires_2fa = false;
    try {
        $stmt = $pdo->prepare("
            SELECT two_factor_enabled 
            FROM member_settings 
            WHERE member_id = ?
        ");
        $stmt->execute([$account['member_id']]);
        $securitySettings = $stmt->fetch(PDO::FETCH_ASSOC);
        $requires_2fa = $securitySettings['two_factor_enabled'] ?? false;
    } catch (Exception $e) {
        error_log("[$requestId] Error checking 2FA status: " . $e->getMessage());
        $requires_2fa = false;
    }

    /* ===============================
     * RESPONSE
     * =============================== */
    $response = [
        'success'      => true,
        'auth_type'    => $authType,
        'requires_2fa' => $requires_2fa,
        'user'         => [
            'member_id'   => $account['member_id'],
            'username'    => $account['username'],
            'email'       => $account['email'],
            'first_name'  => $member['first_name'],
            'last_name'   => $member['last_name'],
            'phone'       => $member['phone_number'],
            'kyc_verified'=> $member['kyc_verified'],
            'preference'  => $member['communication_preference'] ?? 'email'
        ],
        'session_id'   => session_id(),
        'request_id'   => $requestId
    ];
    
    if ($tokens) {
        $response['tokens'] = $tokens;
    }
    
    return $response;
}

// ============================================
// UPDATED 2FA LOGIC USING YOUR EXISTING FUNCTIONS
// ============================================

function handleTwoFactorAuth($account, $authType, $jwtManager, $auditLogger, $requestId) {
    global $pdo;
    
    try {
        $stmt = $pdo->prepare("
            SELECT two_factor_enabled, two_factor_method 
            FROM member_settings 
            WHERE member_id = ?
        ");
        $stmt->execute([$account['member_id']]);
        $securitySettings = $stmt->fetch(PDO::FETCH_ASSOC);
        
        $twoFactorEnabled = $securitySettings['two_factor_enabled'] ?? false;
        $twoFactorMethod = $securitySettings['two_factor_method'] ?? 'email';
        
        if (!$twoFactorEnabled) {
            return ['requires_2fa' => false];
        }
        
        // Use your existing sendOTPByPreference function
        $memberData = [
            'member_id' => $account['member_id'],
            'username' => $account['username'],
            'email' => $account['email'],
            'phone_number' => $account['phone_number'] ?? '',
            'communication_preference' => $account['communication_preference'] ?? 'email',
            'first_name' => $account['first_name'] ?? '',
            'last_name' => $account['last_name'] ?? ''
        ];
        
        // Set preference based on 2FA method
        if ($twoFactorMethod === 'email') {
            $memberData['communication_preference'] = 'email';
        } elseif ($twoFactorMethod === 'sms') {
            $memberData['communication_preference'] = 'sms';
        }
        
        error_log("[$requestId] Sending OTP via method: " . $twoFactorMethod);
        
        // Call your existing sendOTPByPreference function
        $otpSent = sendOTPByPreference($memberData, 'login');
        
        error_log("[$requestId] OTP SEND RESULT: " . ($otpSent ? "SUCCESS" : "FAILED"));
        
        if (!$otpSent) {
            throw new Exception('Failed to send OTP via preferred method');
        }
        
        // Store OTP verification data
        if ($authType === 'session' || $authType === 'hybrid') {
            $_SESSION['2fa_member_id'] = $account['member_id'];
            $_SESSION['2fa_method'] = $twoFactorMethod;
            $_SESSION['2fa_verified'] = false;
            $_SESSION['2fa_sent_time'] = time();
            
            error_log("[$requestId] OTP SUCCESS: Session data set for member " . $account['member_id']);
        }
        
        // For JWT auth, store in temporary table
        $tempToken = null;
        if (($authType === 'jwt' || $authType === 'hybrid') && $jwtManager) {
            $tempToken = $jwtManager->createPreAuthToken($account['member_id'], [
                '2fa_required' => true,
                '2fa_method' => $twoFactorMethod,
                'auth_type' => $authType,
                'user_type' => 'member'
            ]);
        }
        
        if (isset($auditLogger)) {
            $auditLogger->log($account['member_id'], 'login_2fa_initiated', [
                'login_method' => 'login',
                '2fa_method' => $twoFactorMethod,
                'ip' => $_SERVER['REMOTE_ADDR'],
                'auth_type' => $authType,
                'user_type' => 'member',
                'request_id' => $requestId
            ]);
        }
        
        $newCsrfToken = getCsrfToken();
        
        return [
            'requires_2fa' => true,
            'message' => 'Two-factor authentication required. Please verify your identity.',
            'data' => [
                'member_id' => $account['member_id'],
                'first_name' => $account['first_name'] ?? '',
                'last_name' => $account['last_name'] ?? '',
                'redirect_to' => 'verify_2fa.php',
                'csrf_token' => $newCsrfToken,
                'session_id' => session_id(),
                'otp_sent_via' => $twoFactorMethod,
                'auth_type' => $authType,
                'pre_auth_token' => $tempToken,
                'request_id' => $requestId,
                'timestamp' => time(),
                'expires_in' => 300 // OTP valid for 5 minutes
            ]
        ];
        
    } catch (Exception $e) {
        error_log("[$requestId] 2FA handling error: " . $e->getMessage());
        
        if (isset($auditLogger)) {
            $auditLogger->log($account['member_id'] ?? 0, 'login_2fa_error', [
                'ip' => $_SERVER['REMOTE_ADDR'],
                'error' => $e->getMessage(),
                'auth_type' => $authType,
                'request_id' => $requestId
            ]);
        }
        
        return [
            'requires_2fa' => false,
            'error' => '2FA configuration error, proceeding without 2FA'
        ];
    }
}

// ============================================
// INTEGRATED LOGIN NOTIFICATION FUNCTIONS
// ============================================

function sendMemberLoginNotification($account, $member, $ipAddress, $requestId) {
    global $pdo;
    
    // Check if notifications are enabled for this member
    $stmt = $pdo->prepare("
        SELECT setting_value 
        FROM member_settings 
        WHERE member_id = ? AND setting_name = 'login_notifications_enabled'
    ");
    $stmt->execute([$account['member_id']]);
    $notificationsEnabled = $stmt->fetchColumn();
    
    if ($notificationsEnabled !== '1') {
        error_log("[$requestId] Login notifications disabled for member " . $account['member_id']);
        return ['type' => 'skipped', 'message' => 'Login notifications disabled'];
    }

    // Prepare member data using your existing structure
    $memberData = [
        'id' => $account['member_id'],
        'name' => ($member['first_name'] ?? '') . ' ' . ($member['last_name'] ?? ''),
        'username' => $account['username'],
        'email' => $account['email'],
        'phone_number' => $member['phone_number'] ?? '',
        'communication_preference' => $member['communication_preference'] ?? 'email',
        'first_name' => $member['first_name'] ?? '',
        'last_name' => $member['last_name'] ?? ''
    ];
    
    // Get device info
    $deviceInfo = parseMemberUserAgent($_SERVER['HTTP_USER_AGENT'] ?? 'Unknown');
    
    // Get location info
    $location = getLocationFromIP($ipAddress);
    
    // Send login notification using enhanced method
    $notificationResults = sendEnhancedLoginNotification($pdo, $memberData, $ipAddress, $deviceInfo, $location, $requestId);
    
    // Log login notification
    logMemberLoginNotification($pdo, $account['member_id'], $ipAddress, $notificationResults);
    
    // Log security event using your existing function
    logSecurityEvent($account['member_id'], 'login_notification_sent', [
        'ip' => $ipAddress,
        'device' => $deviceInfo,
        'location' => $location
    ]);
    
    return $notificationResults;
}

function sendEnhancedLoginNotification($pdo, $memberData, $ipAddress, $deviceInfo, $location, $requestId) {
    global $smtpConfig;
    
    $results = [
        'sms' => ['type' => 'skipped', 'message' => 'No phone number or SMS not configured'],
        'email' => ['type' => 'skipped', 'message' => 'Email notification not configured'],
        'internal' => ['type' => 'success', 'message' => 'Internal notification recorded']
    ];

    // Get company settings
    $companySettings = $pdo->query("SELECT company_name, portal_url FROM company_settings LIMIT 1")->fetch();
    $companyName = $companySettings['company_name'] ?? 'Creative SACCO';
    $portalUrl = $companySettings['portal_url'] ?? getAppUrl();
    
    $loginTime = date('Y-m-d H:i:s');
    
    // 1. SMS Notification using your existing sendSms function
    if (!empty($memberData['phone_number']) && validateKenyanPhoneNumber($memberData['phone_number'])) {
        try {
            $cleanPhone = preg_replace('/[^0-9]/', '', $memberData['phone_number']);
            $smsMessage = "Hello {$memberData['name']}, new login detected on {$deviceInfo} from {$location} at {$loginTime}. If this wasn't you, contact support.";
            
            // Use your existing sendSms function
            if (function_exists('sendSms')) {
                $smsResult = sendSms($pdo, $cleanPhone, $smsMessage, null, true);
                
                if ($smsResult['type'] === 'error') {
                    $results['sms'] = ['type' => 'error', 'message' => $smsResult['message']];
                    error_log("[$requestId] Login SMS failed for {$cleanPhone}: " . $smsResult['message']);
                } else {
                    $results['sms'] = ['type' => 'success', 'message' => 'SMS sent successfully'];
                    error_log("[$requestId] Login SMS sent to {$cleanPhone}");
                }
            } else {
                error_log("[$requestId] sendSms function not available");
                $results['sms'] = ['type' => 'error', 'message' => 'SMS function not available'];
            }
            
        } catch (Exception $e) {
            $results['sms'] = ['type' => 'error', 'message' => $e->getMessage()];
            error_log("[$requestId] SMS notification error: " . $e->getMessage());
        }
    }

    // 2. Email Notification - Using your existing sendOTPByPreference structure
    if (!empty($memberData['email'])) {
        try {
            // Use your existing sendOTPEmail function structure
            $subject = "New Login Detected - {$companyName}";
            $body = "Dear {$memberData['name']},\n\n" .
                   "A new login was detected on your account:\n\n" .
                   "• Time: {$loginTime}\n" .
                   "• IP Address: {$ipAddress}\n" .
                   "• Location: {$location}\n" .
                   "• Device: {$deviceInfo}\n\n" .
                   "If this wasn't you, please contact support immediately.\n\n" .
                   "Best regards,\n" .
                   "{$companyName} Security Team";
            
            // Load SMTP configuration
            $smtpConfig = loadSmtpConfig();
            
            if ($smtpConfig && class_exists('PHPMailer\PHPMailer\PHPMailer')) {
                // Create PHPMailer instance similar to your sendOTPEmail
                $mail = new PHPMailer\PHPMailer\PHPMailer(true);
                
                $mail->isSMTP();
                $mail->Host = $smtpConfig['host'];
                $mail->SMTPAuth = true;
                $mail->Username = $smtpConfig['username'];
                $mail->Password = $smtpConfig['password'];
                $mail->SMTPSecure = $smtpConfig['encryption'];
                $mail->Port = $smtpConfig['port'];
                
                $mail->setFrom($smtpConfig['from_address'], $smtpConfig['from_name']);
                $mail->addAddress($memberData['email']);
                
                $mail->isHTML(true);
                $mail->Subject = $subject;
                $mail->Body = nl2br($body);
                $mail->AltBody = $body;
                
                if ($mail->send()) {
                    $results['email'] = ['type' => 'success', 'message' => 'Email sent successfully'];
                    error_log("[$requestId] Login email sent to " . $memberData['email']);
                } else {
                    $results['email'] = ['type' => 'error', 'message' => 'Failed to send email'];
                    error_log("[$requestId] Failed to send email to " . $memberData['email']);
                }
            } else {
                // Fallback to simple mail()
                $headers = "From: " . ($smtpConfig['from_address'] ?? 'noreply@creativesacco.com');
                if (mail($memberData['email'], $subject, $body, $headers)) {
                    $results['email'] = ['type' => 'success', 'message' => 'Email sent via mail()'];
                } else {
                    $results['email'] = ['type' => 'error', 'message' => 'mail() function failed'];
                }
            }
            
        } catch (Exception $e) {
            $results['email'] = ['type' => 'error', 'message' => $e->getMessage()];
            error_log("[$requestId] Email notification error: " . $e->getMessage());
        }
    }

    return $results;
}

function parseMemberUserAgent($userAgent) {
    if (empty($userAgent)) {
        return 'Unknown Device';
    }
    
    $userAgent = strtolower($userAgent);
    
    if (strpos($userAgent, 'mobile') !== false) {
        return 'Mobile Device';
    } elseif (strpos($userAgent, 'tablet') !== false) {
        return 'Tablet';
    } elseif (strpos($userAgent, 'windows') !== false || 
              strpos($userAgent, 'macintosh') !== false || 
              strpos($userAgent, 'linux') !== false) {
        return 'Desktop Computer';
    } else {
        return 'Unknown Device';
    }
}

function logMemberLoginNotification($pdo, $memberId, $ipAddress, $notificationResults) {
    try {
        $stmt = $pdo->prepare("
            INSERT INTO member_login_notifications 
            (member_id, ip_address, notification_type, sent_at, sms_status, email_status) 
            VALUES (?, ?, 'login', NOW(), ?, ?)
        ");
        
        $smsStatus = isset($notificationResults['sms']) ? $notificationResults['sms']['type'] : 'skipped';
        $emailStatus = isset($notificationResults['email']) ? $notificationResults['email']['type'] : 'skipped';
        
        $stmt->execute([$memberId, $ipAddress, $smsStatus, $emailStatus]);
    } catch (Exception $e) {
        error_log("Failed to log member login notification: " . $e->getMessage());
    }
}

function getAppUrl() {
    $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
    $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
    return $protocol . '://' . $host;
}

function getLocationFromIP($ip) {
    if ($ip === '127.0.0.1' || $ip === '::1') {
        return 'Localhost';
    }
    
    // Simple implementation
    try {
        if (function_exists('curl_init')) {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, "https://ipapi.co/{$ip}/country_name/");
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_TIMEOUT, 2);
            curl_setopt($ch, CURLOPT_USERAGENT, 'CreativeSACCO-LoginSystem/1.0');
            $response = curl_exec($ch);
            curl_close($ch);
            
            if ($response && $response !== 'Undefined' && $response !== 'Not Found') {
                return $response;
            }
        }
    } catch (Exception $e) {
        // Silently fail
    }
    
    return 'Unknown Location';
}

// ============================================
// API ENDPOINTS
// ============================================

// GET: Initialize session
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    try {
        if (!isset($_SESSION['login_attempts'])) {
            $_SESSION['login_attempts'] = 0;
            $_SESSION['last_login_attempt'] = 0;
            error_log("DEBUG: Login attempts initialized");
        }
        
        // Fetch company name
        $companyName = 'Creative SACCO';
        try {
            $stmt = $pdo->query("SELECT company_name FROM company_settings LIMIT 1");
            $companyName = $stmt->fetchColumn() ?: 'Creative SACCO';
            $_SESSION['company_name'] = $companyName;
        } catch (Exception $e) {
            error_log("[$requestId] Failed to fetch company name: " . $e->getMessage());
        }
        
        $csrfToken = getCsrfToken();
        
        sendResponse([
            'success' => true,
            'data' => [
                'csrf_token' => $csrfToken,
                'company_name' => $companyName,
                'session_id' => session_id(),
                'timestamp' => time(),
                'server_time' => date('Y-m-d H:i:s'),
                'login_options' => ['Email', 'Username', 'Phone', 'ID Number']
            ],
            'meta' => [
                'request_id' => $requestId
            ]
        ]);
        
    } catch (Exception $e) {
        error_log("[$requestId] GET endpoint error: " . $e->getMessage());
        sendResponse([
            'success' => false,
            'message' => 'Initialization failed',
            'request_id' => $requestId
        ], 500);
    }
}

// POST: Handle login
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    try {
        $input = getJsonInput();
        
        if (!$input) {
            sendResponse([
                'success' => false,
                'message' => 'Invalid JSON input',
                'request_id' => $requestId
            ], 400);
        }
        
        $login = isset($input['username']) ? trim($input['username']) : '';
        $password = $input['password'] ?? '';
        $csrf_token = $input['csrf_token'] ?? '';
        $remember_me = isset($input['remember_me']) && $input['remember_me'] === true;
        $auth_type = isset($input['auth_type']) ? $input['auth_type'] : 'hybrid';
        $device_id = isset($input['device_id']) ? $input['device_id'] : '';
        $honeypot = $input['honeypot'] ?? '';

        error_log("[$requestId] Login attempt for: " . (empty($login) ? 'EMPTY' : substr($login, 0, 3) . "***"));

        // Honeypot check
        if (!empty($honeypot)) {
            error_log("[$requestId] SECURITY: Honeypot triggered");
            logSecurityEvent(null, 'bot_detected', ['reason' => 'honeypot_triggered']);
            sendResponse([
                'success' => false,
                'message' => 'Invalid request',
                'request_id' => $requestId
            ], 403);
        }

        // Fallback to session if JWT unavailable
        if (($auth_type === 'jwt' || $auth_type === 'hybrid') && !$jwtManager) {
            if ($auth_type === 'hybrid') {
                $auth_type = 'session';
                error_log("[$requestId] Falling back to session authentication");
            } else if ($auth_type === 'jwt') {
                sendResponse([
                    'success' => false,
                    'message' => 'JWT authentication unavailable',
                    'request_id' => $requestId
                ], 503);
            }
        }

        // Validate required fields
        if (empty($login) || empty($password)) {
            if (isset($auditLogger)) {
                $auditLogger->log(0, 'login_failed_missing_credentials', [
                    'attempted_login' => substr($login, 0, 3) . '***',
                    'ip' => $_SERVER['REMOTE_ADDR'],
                    'auth_type' => $auth_type,
                    'request_id' => $requestId
                ]);
            }
            sendResponse([
                'success' => false,
                'message' => 'Login identifier and password are required',
                'request_id' => $requestId
            ], 400);
        }

        // Validate login identifier
        $identifierValidation = validateLoginIdentifier($login);
        if (!$identifierValidation['valid']) {
            if (isset($auditLogger)) {
                $auditLogger->log(0, 'login_failed_invalid_format', [
                    'attempted_login' => substr($login, 0, 3) . '***',
                    'ip' => $_SERVER['REMOTE_ADDR'],
                    'auth_type' => $auth_type,
                    'request_id' => $requestId
                ]);
            }
            sendResponse([
                'success' => false,
                'message' => 'Invalid login format. Use email, username, phone, or ID number',
                'request_id' => $requestId
            ], 400);
        }

        // CSRF validation for web logins
        if ($auth_type === 'session' || $auth_type === 'hybrid') {
            if (empty($csrf_token)) {
                if (isset($auditLogger)) {
                    $auditLogger->log(0, 'login_failed_missing_csrf', [
                        'attempted_login' => substr($login, 0, 3) . '***',
                        'ip' => $_SERVER['REMOTE_ADDR'],
                        'auth_type' => $auth_type,
                        'request_id' => $requestId
                    ]);
                }
                sendResponse([
                    'success' => false,
                    'message' => 'Security token required',
                    'request_id' => $requestId
                ], 400);
            }

            // Enhanced CSRF check with debugging
            $postToken = $csrf_token;
            $sessionToken = $_SESSION['csrf_token'] ?? '';
            
            if (empty($sessionToken)) {
                error_log("[$requestId] CSRF FAIL: Empty session token");
                $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
                sendResponse([
                    'success' => false,
                    'message' => 'Invalid request (session issue). Please refresh the page and try again.',
                    'request_id' => $requestId
                ], 403);
            }
            
            if (!hash_equals($sessionToken, $postToken)) {
                if (isset($auditLogger)) {
                    $auditLogger->log(0, 'csrf_validation_failed', [
                        'attempted_login' => substr($login, 0, 3) . '***',
                        'ip' => $_SERVER['REMOTE_ADDR'],
                        'auth_type' => $auth_type,
                        'request_id' => $requestId
                    ]);
                }
                
                $newToken = getCsrfToken();
                sendResponse([
                    'success' => false,
                    'message' => 'Invalid or expired security token',
                    'data' => ['new_csrf_token' => $newToken],
                    'request_id' => $requestId
                ], 403);
            }

            // Clear CSRF token after use
            unset($_SESSION['csrf_token']);
            unset($_SESSION['csrf_token_time']);
        }

        $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        error_log("[$requestId] IP Address: $ip");

        // Rate limiting
        $currentTime = time();
        $rateLimitKey = 'login_attempts_' . md5($login . $ip);
        
        if (!isset($_SESSION[$rateLimitKey])) {
            $_SESSION[$rateLimitKey] = [
                'attempts' => 0,
                'reset_time' => $currentTime,
                'last_attempt' => 0
            ];
        }
        
        $rateData = $_SESSION[$rateLimitKey];
        
        if (($currentTime - $rateData['reset_time']) > 3600) {
            $rateData['attempts'] = 0;
            $rateData['reset_time'] = $currentTime;
        }
        
        if ($rateData['attempts'] >= 5 && ($currentTime - $rateData['last_attempt']) < 300) {
            $waitTime = 300 - ($currentTime - $rateData['last_attempt']);
            
            if (isset($auditLogger)) {
                $auditLogger->log(0, 'rate_limit_exceeded', [
                    'attempted_login' => substr($login, 0, 3) . '***',
                    'ip' => $ip,
                    'attempts' => $rateData['attempts'],
                    'wait_time' => $waitTime,
                    'auth_type' => $auth_type,
                    'request_id' => $requestId
                ]);
            }
            
            sendResponse([
                'success' => false,
                'message' => "Too many attempts. Wait $waitTime seconds",
                'request_id' => $requestId
            ], 429);
        }

        $rateData['attempts']++;
        $rateData['last_attempt'] = $currentTime;
        $_SESSION[$rateLimitKey] = $rateData;

        // IP-based rate limiting
        $ipAttempts = checkIpRateLimit($ip, $pdo, $requestId);
        if ($ipAttempts > 10) {
            if (isset($auditLogger)) {
                $auditLogger->log(0, 'ip_rate_limit_exceeded', [
                    'attempted_login' => substr($login, 0, 3) . '***',
                    'ip' => $ip,
                    'ip_attempts' => $ipAttempts,
                    'auth_type' => $auth_type,
                    'request_id' => $requestId
                ]);
            }
            sendResponse([
                'success' => false,
                'message' => 'Too many attempts from your IP',
                'request_id' => $requestId
            ], 429);
        }
        
        // Record IP attempt
        try {
            $pdo->prepare("INSERT INTO login_attempts (ip_address, attempted_at, login_type) VALUES (?, NOW(), 'member')")->execute([$ip]);
        } catch (Exception $e) {
            error_log("[$requestId] Failed to log IP attempt: " . $e->getMessage());
        }

        // Fetch member account with enhanced query
        $sql = "
            SELECT a.member_id, a.username, a.email, a.password_hash, a.status, a.password_last_changed,
                   a.lock_expires, a.last_login,
                   m.first_name, m.last_name, m.kyc_verified, m.kyc_verified_at,
                   m.kyc_attempts, m.kyc_locked, m.communication_preference, m.phone_number,
                   m.id_number
            FROM member_portal_accounts a
            JOIN members m ON m.id = a.member_id
            WHERE (a.username = :login OR a.email = :login";
        
        $queryParams = ['login' => $login];
        
        if ($identifierValidation['type'] === 'phone' && isset($identifierValidation['normalized'])) {
            $normalizedPhone = $identifierValidation['normalized'];
            $sql .= " OR REPLACE(REPLACE(REPLACE(m.phone_number, '+', ''), ' ', ''), '-', '') = :phone";
            $queryParams['phone'] = $normalizedPhone;
        }
        
        if ($identifierValidation['type'] === 'id_number') {
            $sql .= " OR m.id_number = :id_number";
            $queryParams['id_number'] = $login;
        }
        
        $sql .= ") AND a.status = 'active' LIMIT 1";
        
        $stmt = $pdo->prepare($sql);
        $stmt->execute($queryParams);
        $account = $stmt->fetch(PDO::FETCH_ASSOC);
        
        $member = [];
        if ($account) {
            $member = [
                'member_id' => $account['member_id'],
                'first_name' => $account['first_name'],
                'last_name' => $account['last_name'],
                'phone_number' => $account['phone_number'],
                'id_number' => $account['id_number'],
                'kyc_verified' => $account['kyc_verified'],
                'kyc_attempts' => $account['kyc_attempts'],
                'kyc_locked' => $account['kyc_locked'],
                'communication_preference' => $account['communication_preference']
            ];
        }
        
        error_log("[$requestId] ACCOUNT LOOKUP: " . ($account ? "FOUND - " . $account['username'] : "NOT FOUND"));
        
        // Timing attack protection
        usleep(500000);
        
        $validPassword = $account && password_verify($password, $account['password_hash']);
        // Dummy verification for timing protection
        password_verify('dummy_password', '$2y$10$dummyhashforprotection');

        error_log("[$requestId] PASSWORD VERIFICATION: " . ($validPassword ? "VALID" : "INVALID"));

        if (!$validPassword) {
            error_log("[$requestId] Login failed for $login");
            
            // Log security event using your existing function
            logSecurityEvent($account['member_id'] ?? 0, 'login_failed', [
                'login_identifier' => substr($login, 0, 3) . '***',
                'ip' => $ip,
                'auth_type' => $auth_type,
                'request_id' => $requestId
            ]);
            
            if (isset($auditLogger)) {
                $memberId = $account['member_id'] ?? 0;
                $auditLogger->log($memberId, 'login_failed_invalid_credentials', [
                    'attempted_login' => substr($login, 0, 3) . '***',
                    'login_method' => $identifierValidation['type'],
                    'ip' => $ip,
                    'attempt_number' => $rateData['attempts'],
                    'member_exists' => !empty($account),
                    'auth_type' => $auth_type,
                    'request_id' => $requestId
                ]);
            }
            
            // Lock account after 5 failed attempts
            if ($rateData['attempts'] >= 5 && $account) {
                $lockExpires = date('Y-m-d H:i:s', time() + 300);
                $pdo->prepare("
                    UPDATE member_portal_accounts 
                    SET status = 'suspended', 
                        lock_expires = ?,
                        failed_attempts = failed_attempts + 1
                    WHERE member_id = ?
                ")->execute([$lockExpires, $account['member_id']]);
                
                // Log security event
                logSecurityEvent($account['member_id'], 'account_locked', [
                    'reason' => 'too_many_failed_attempts',
                    'attempts' => $rateData['attempts'],
                    'lock_duration' => '5 minutes'
                ]);
                
                if (isset($auditLogger)) {
                    $auditLogger->log($account['member_id'], 'account_auto_locked', [
                        'reason' => 'too_many_failed_attempts',
                        'attempts' => $rateData['attempts'],
                        'ip' => $ip,
                        'lock_duration' => '5 minutes',
                        'auth_type' => $auth_type,
                        'request_id' => $requestId
                    ]);
                }
            }
            
            $newCsrfToken = getCsrfToken();
            
            sendResponse([
                'success' => false,
                'message' => 'Invalid login or password',
                'data' => [
                    'login_attempts' => $rateData['attempts'],
                    'csrf_token' => $newCsrfToken
                ],
                'request_id' => $requestId
            ], 401);
        }

        // VALID CREDENTIALS
        error_log("[$requestId] Valid credentials for member ID: " . $account['member_id']);
        
        // Check password rehashing
        if (password_needs_rehash($account['password_hash'], PASSWORD_DEFAULT)) {
            $newHash = password_hash($password, PASSWORD_DEFAULT);
            $pdo->prepare("UPDATE member_portal_accounts SET password_hash = ? WHERE member_id = ?")
                ->execute([$newHash, $account['member_id']]);
            error_log("[$requestId] PASSWORD REHASHED: Password upgraded to new algorithm");
        }

        // Check account status
        if ($account['status'] !== 'active') {
            $lockExpiresRaw = $account['lock_expires'] ?? null;
            $isLocked = false;
            $lockReason = '';
            
            if (!empty($lockExpiresRaw)) {
                $expiryTs = strtotime($lockExpiresRaw);
                
                if ($expiryTs === false) {
                    $isLocked = true;
                    $lockReason = 'suspended';
                } elseif ($expiryTs > time()) {
                    $isLocked = true;
                    $lockReason = 'locked_until';
                } else {
                    // Auto-unlock
                    $pdo->prepare("
                        UPDATE member_portal_accounts 
                        SET status = 'active', lock_expires = NULL
                        WHERE member_id = ?
                    ")->execute([$account['member_id']]);
                    
                    $account['status'] = 'active';
                    $account['lock_expires'] = null;
                    
                    logSecurityEvent($account['member_id'], 'account_auto_unlocked', [
                        'ip' => $ip
                    ]);
                    error_log("[$requestId] ACCOUNT AUTO-UNLOCKED: " . $account['member_id']);
                }
            } else {
                $isLocked = true;
                $lockReason = 'suspended';
            }
            
            if ($isLocked) {
                logSecurityEvent($account['member_id'], 'login_blocked', [
                    'reason' => $lockReason,
                    'account_status' => $account['status']
                ]);
                
                if (isset($auditLogger)) {
                    $auditLogger->log($account['member_id'], 'login_blocked_account_locked', [
                        'login_method' => $identifierValidation['type'],
                        'ip' => $ip,
                        'lock_reason' => $lockReason,
                        'auth_type' => $auth_type,
                        'request_id' => $requestId
                    ]);
                }
                
                sendResponse([
                    'success' => false,
                    'message' => $lockReason === 'suspended' 
                        ? 'Account suspended. Contact support.' 
                        : "Account locked until {$account['lock_expires']}",
                    'request_id' => $requestId
                ], 423);
            }
        }

        // Check KYC lock
        if ($account['kyc_locked']) {
            logSecurityEvent($account['member_id'], 'login_blocked_kyc', [
                'kyc_verified' => $account['kyc_verified'],
                'kyc_locked' => true
            ]);
            
            if (isset($auditLogger)) {
                $auditLogger->log($account['member_id'], 'login_kyc_locked', [
                    'login_method' => $identifierValidation['type'],
                    'ip' => $ip,
                    'auth_type' => $auth_type,
                    'request_id' => $requestId
                ]);
            }
            
            sendResponse([
                'success' => false,
                'message' => 'KYC locked. Contact support.',
                'request_id' => $requestId
            ], 403);
        }

        // Check KYC verification
        if (!$account['kyc_verified']) {
            if ($auth_type === 'session' || $auth_type === 'hybrid') {
                $_SESSION['kyc_member_id'] = $account['member_id'];
            }
            
            logSecurityEvent($account['member_id'], 'login_kyc_required', [
                'kyc_verified' => false
            ]);
            
            if (isset($auditLogger)) {
                $auditLogger->log($account['member_id'], 'login_kyc_required', [
                    'login_method' => $identifierValidation['type'],
                    'ip' => $ip,
                    'auth_type' => $auth_type,
                    'request_id' => $requestId
                ]);
            }
            
            sendResponse([
                'success' => false,
                'message' => 'KYC verification required',
                'data' => [
                    'redirect' => 'kyc_verification.php',
                    'auth_type' => $auth_type,
                    'member_id' => $account['member_id'],
                    'request_id' => $requestId
                ]
            ]);
        }

        // Reset login attempts
        unset($_SESSION[$rateLimitKey]);
        
        // Check password expiration
        if (!empty($account['password_last_changed'])) {
            $passwordLastChanged = strtotime($account['password_last_changed']);
            $expiryTime = $passwordLastChanged + (90 * 24 * 60 * 60);

            if (time() > $expiryTime) {
                if ($auth_type === 'session' || $auth_type === 'hybrid') {
                    $_SESSION['force_password_reset'] = true;
                    $_SESSION['member_id'] = $account['member_id'];
                }
                
                logSecurityEvent($account['member_id'], 'password_expired', [
                    'last_changed' => $account['password_last_changed']
                ]);
                
                if (isset($auditLogger)) {
                    $auditLogger->log($account['member_id'], 'login_password_reset_required', [
                        'login_method' => $identifierValidation['type'],
                        'ip' => $ip,
                        'auth_type' => $auth_type,
                        'request_id' => $requestId
                    ]);
                }
                
                sendResponse([
                    'success' => false,
                    'message' => 'Password reset required',
                    'data' => [
                        'redirect' => 'force_password_reset.php',
                        'auth_type' => $auth_type,
                        'member_id' => $account['member_id'],
                        'request_id' => $requestId
                    ]
                ]);
            }
        }

        // Check 2FA using updated function
        $twoFactorResult = handleTwoFactorAuth($account, $auth_type, $jwtManager, $auditLogger, $requestId);
        
        if ($twoFactorResult['requires_2fa']) {
            // Send 2FA required response with requires_2fa field
            sendResponse([
                'success' => true,
                'requires_2fa' => true,
                'message' => $twoFactorResult['message'],
                'data' => $twoFactorResult['data']
            ], 200);
        }

        // Complete login (2FA not required)
        error_log("[$requestId] Completing login for ID: " . $account['member_id']);
        
        // Update last login
        $pdo->prepare("UPDATE member_portal_accounts SET last_login = NOW() WHERE member_id = ?")
            ->execute([$account['member_id']]);
        error_log("[$requestId] LAST LOGIN UPDATED: " . $account['member_id']);
        
        // Send login notification (but don't fail login if notifications fail)
        try {
            $notificationResult = sendMemberLoginNotification($account, $member, $ip, $requestId);
            error_log("[$requestId] Login notification result: " . json_encode($notificationResult));
        } catch (Exception $e) {
            error_log("[$requestId] Login notification failed (non-critical): " . $e->getMessage());
        }
        
        // Log successful login
        logSecurityEvent($account['member_id'], 'login_successful', [
            'ip' => $ip,
            'auth_type' => $auth_type,
            'login_method' => $identifierValidation['type']
        ]);
        
        $loginResult = completeLogin($account, $member, $auditLogger, $jwtManager, $identifierValidation['type'], $remember_me, $auth_type, $device_id, $requestId);
        
        sendResponse($loginResult);

    } catch (Exception $e) {
        error_log("[$requestId] Login processing error: " . $e->getMessage());
        
        // Log error using your security function
        logSecurityEvent(0, 'login_system_error', [
            'error' => $e->getMessage(),
            'ip' => $_SERVER['REMOTE_ADDR'],
            'request_id' => $requestId
        ]);
        
        if (isset($auditLogger)) {
            $auditLogger->log(0, 'login_processing_error', [
                'ip' => $_SERVER['REMOTE_ADDR'],
                'error' => $e->getMessage(),
                'request_id' => $requestId
            ]);
        }
        
        sendResponse([
            'success' => false,
            'message' => 'An error occurred. Please try again.',
            'request_id' => $requestId
        ], 500);
    }
}

// Invalid method
sendResponse([
    'success' => false,
    'message' => 'Method not allowed',
    'request_id' => $requestId
], 405);

error_log("[$requestId] === LOGIN REQUEST END ===");
?>