<?php
/**
 * Enterprise HRM ERP System - Authentication & Authorization
 * Multi-site, Multi-HR, Role-based System
 */

// Prevent direct access
if (!defined('HRM_ACCESS')) {
    die('Direct access not allowed');
}

/**
 * Start session if not started
 */
function startSession() {
    if (session_status() === PHP_SESSION_NONE) {
        $sessionTimeout = getSetting('SESSION_TIMEOUT', SESSION_LIFETIME);
        ini_set('session.gc_maxlifetime', $sessionTimeout);
        session_name(SESSION_NAME);
        session_start();
        
        // Check session timeout
        if (isset($_SESSION['last_activity']) && 
            (time() - $_SESSION['last_activity']) > $sessionTimeout) {
            session_destroy();
            session_start();
        }
        
        $_SESSION['last_activity'] = time();
    }
}

/**
 * Check if user is logged in
 */
function isLoggedIn() {
    startSession();
    // User is logged in if user_id is set
    // site_id is optional (super_admin might not have a site)
    return isset($_SESSION['user_id']);
}

/**
 * Require login
 */
function requireLogin() {
    if (!isLoggedIn()) {
        $_SESSION['redirect_after_login'] = $_SERVER['REQUEST_URI'];
        header('Location: ' . BASE_URL . '/login.php');
        exit;
    }
}

/**
 * Login user
 */
function login($username, $password) {
    try {
        $db = getDB();
        
        // Check if account is locked
        $stmt = $db->prepare("
            SELECT user_id, username, password_hash, user_status, failed_login_attempts, locked_until, site_id
            FROM users 
            WHERE username = ? OR email = ?
        ");
        $stmt->execute([$username, $username]);
        $user = $stmt->fetch();
        
        if (!$user) {
            return ['success' => false, 'message' => 'Invalid username or password.'];
        }
        
        // Check if account is locked
        if ($user['locked_until'] && strtotime($user['locked_until']) > time()) {
            $lockedUntil = formatDateTime($user['locked_until']);
            return ['success' => false, 'message' => "Account is locked until {$lockedUntil}. Please try again later."];
        }
        
        // Check if account is inactive
        if ($user['user_status'] !== 'active') {
            return ['success' => false, 'message' => 'Your account is inactive. Please contact administrator.'];
        }
        
        // Verify password
        if (!verifyPassword($password, $user['password_hash'])) {
            // Increment failed login attempts
            $maxAttempts = getSetting('MAX_LOGIN_ATTEMPTS', 5);
            $lockoutDuration = getSetting('LOCKOUT_DURATION', 1800);
            $failedAttempts = $user['failed_login_attempts'] + 1;
            
            if ($failedAttempts >= $maxAttempts) {
                $lockedUntil = date('Y-m-d H:i:s', time() + $lockoutDuration);
                $stmt = $db->prepare("
                    UPDATE users 
                    SET failed_login_attempts = ?, locked_until = ?
                    WHERE user_id = ?
                ");
                $stmt->execute([$failedAttempts, $lockedUntil, $user['user_id']]);
                
                return ['success' => false, 'message' => 'Too many failed login attempts. Account locked for ' . ($lockoutDuration / 60) . ' minutes.'];
            } else {
                $stmt = $db->prepare("UPDATE users SET failed_login_attempts = ? WHERE user_id = ?");
                $stmt->execute([$failedAttempts, $user['user_id']]);
                
                $remaining = $maxAttempts - $failedAttempts;
                return ['success' => false, 'message' => "Invalid username or password. {$remaining} attempt(s) remaining."];
            }
        }
        
        // Reset failed login attempts
        $stmt = $db->prepare("
            UPDATE users 
            SET failed_login_attempts = 0, locked_until = NULL, last_login = NOW()
            WHERE user_id = ?
        ");
        $stmt->execute([$user['user_id']]);
        
        // Get user permissions (handle if permissions table doesn't exist)
        $permissions = [];
        try {
            // Check if permissions table exists
            $stmt = $db->query("SHOW TABLES LIKE 'permissions'");
            if ($stmt->rowCount() > 0) {
                // Table exists, fetch permissions
        $stmt = $db->prepare("
            SELECT p.permission_code
            FROM permissions p
            INNER JOIN role_permissions rp ON p.permission_id = rp.permission_id
            INNER JOIN users u ON rp.role_id = u.role_id
            WHERE u.user_id = ?
        ");
        $stmt->execute([$user['user_id']]);
        $permissions = $stmt->fetchAll(PDO::FETCH_COLUMN);
            } else {
                // Permissions table doesn't exist, use empty array
                error_log("Warning: permissions table not found. Login will proceed without permissions.");
                $permissions = [];
            }
        } catch (Exception $e) {
            // If any error occurs, just use empty permissions array
            error_log("Warning: Could not fetch permissions: " . $e->getMessage());
            $permissions = [];
        }
        
        // Get user details with role and site info
        $stmt = $db->prepare("
            SELECT u.*, r.role_name, r.role_code, r.role_id,
                   COALESCE(s.site_name, 'N/A') as site_name, 
                   COALESCE(s.site_code, 'N/A') as site_code
            FROM users u
            LEFT JOIN roles r ON u.role_id = r.role_id
            LEFT JOIN sites s ON u.site_id = s.site_id
            WHERE u.user_id = ?
        ");
        $stmt->execute([$user['user_id']]);
        $userDetails = $stmt->fetch();
        
        if (!$userDetails) {
            error_log("Login error: User details not found for user_id={$user['user_id']}");
            return ['success' => false, 'message' => 'Error loading user details. Please contact administrator.'];
        }
        
        // Ensure role_code is set - handle case where role might not exist
        if (empty($userDetails['role_code']) || empty($userDetails['role_id'])) {
            // Try to get role_code directly
            if (!empty($userDetails['role_id'])) {
            $stmt = $db->prepare("SELECT role_code FROM roles WHERE role_id = ?");
            $stmt->execute([$userDetails['role_id']]);
            $role = $stmt->fetch();
                if ($role && !empty($role['role_code'])) {
                $userDetails['role_code'] = $role['role_code'];
                } else {
                    // If no role found, assign default admin role
                    $stmt = $db->prepare("SELECT role_id, role_code FROM roles WHERE role_code = 'super_admin' OR role_code = 'admin' LIMIT 1");
                    $stmt->execute();
                    $defaultRole = $stmt->fetch();
                    if ($defaultRole) {
                        $userDetails['role_id'] = $defaultRole['role_id'];
                        $userDetails['role_code'] = $defaultRole['role_code'];
                        // Update user's role
                        $stmt = $db->prepare("UPDATE users SET role_id = ? WHERE user_id = ?");
                        $stmt->execute([$defaultRole['role_id'], $user['user_id']]);
                    } else {
                        $userDetails['role_code'] = 'employee'; // Ultimate fallback
                    }
                }
            } else {
                // No role_id at all - assign default admin role
                $stmt = $db->prepare("SELECT role_id, role_code FROM roles WHERE role_code = 'super_admin' OR role_code = 'admin' LIMIT 1");
                $stmt->execute();
                $defaultRole = $stmt->fetch();
                if ($defaultRole) {
                    $userDetails['role_id'] = $defaultRole['role_id'];
                    $userDetails['role_code'] = $defaultRole['role_code'];
                    // Update user's role
                    $stmt = $db->prepare("UPDATE users SET role_id = ? WHERE user_id = ?");
                    $stmt->execute([$defaultRole['role_id'], $user['user_id']]);
                } else {
                    error_log("Login error: No default role found for user_id={$user['user_id']}");
                    return ['success' => false, 'message' => 'User role not configured. Please contact administrator.'];
                }
            }
        }
        
        // Get primary site from user_sites if available (handle if table doesn't exist)
        $siteId = $user['site_id'] ?? null;
        $siteName = $userDetails['site_name'] ?? 'N/A';
        $siteCode = $userDetails['site_code'] ?? 'N/A';
        $userSites = [];
        
        try {
            // Check if user_sites table exists
            $stmt = $db->query("SHOW TABLES LIKE 'user_sites'");
            if ($stmt->rowCount() > 0) {
                // Table exists, fetch all user sites
                $stmt = $db->prepare("
                    SELECT s.site_id, s.site_name, s.site_code, us.is_primary
                    FROM user_sites us
                    INNER JOIN sites s ON us.site_id = s.site_id
                    WHERE us.user_id = ? AND s.site_status = 'active'
                    ORDER BY us.is_primary DESC, s.site_name
                ");
                $stmt->execute([$user['user_id']]);
                $userSites = $stmt->fetchAll();
                
                // Get primary site
                $primarySite = null;
                foreach ($userSites as $us) {
                    if ($us['is_primary'] == 1) {
                        $primarySite = $us;
                        break;
                    }
                }
                
                // If no primary, use first site
                if (!$primarySite && count($userSites) > 0) {
                    $primarySite = $userSites[0];
                }
                
                if ($primarySite) {
                    $siteId = $primarySite['site_id'];
                    $siteName = $primarySite['site_name'];
                    $siteCode = $primarySite['site_code'];
                }
            }
        } catch (Exception $e) {
            // If user_sites table doesn't exist or any error, use default site from user
            error_log("Warning: Could not fetch primary site from user_sites: " . $e->getMessage());
        }
        
        // If user has multiple branches and no branch selected in POST, return branch selection
        if (count($userSites) > 1 && !isset($_POST['selected_site_id'])) {
            // Store user data temporarily for branch selection
            startSession();
            $_SESSION['temp_user_id'] = $user['user_id'];
            $_SESSION['temp_username'] = $user['username'];
            $_SESSION['temp_user_sites'] = $userSites;
            $_SESSION['temp_role_code'] = $userDetails['role_code'];
            $_SESSION['temp_full_name'] = $userDetails['full_name'];
            $_SESSION['temp_permissions'] = $permissions;
            
            return [
                'success' => false, 
                'message' => 'branch_selection_required',
                'sites' => $userSites,
                'user_id' => $user['user_id']
            ];
        }
        
        // If branch selected in POST, use that
        if (isset($_POST['selected_site_id']) && is_numeric($_POST['selected_site_id'])) {
            $selectedSiteId = (int)$_POST['selected_site_id'];
            // Verify site is in user's accessible sites
            $found = false;
            foreach ($userSites as $us) {
                if ($us['site_id'] == $selectedSiteId) {
                    $siteId = $selectedSiteId;
                    $siteName = $us['site_name'];
                    $siteCode = $us['site_code'];
                    $found = true;
                    break;
                }
            }
            if (!$found && count($userSites) > 0) {
                // Invalid site selected, use primary
                $primarySite = $userSites[0];
                $siteId = $primarySite['site_id'];
                $siteName = $primarySite['site_name'];
                $siteCode = $primarySite['site_code'];
            }
        }
        
        // Set session variables
        startSession();
        $_SESSION['user_id'] = $user['user_id'];
        $_SESSION['site_id'] = $siteId;
        $_SESSION['username'] = $user['username'];
        $_SESSION['full_name'] = $userDetails['full_name'];
        $_SESSION['role_id'] = $userDetails['role_id'];
        $_SESSION['role_code'] = $userDetails['role_code']; // Already ensured above
        $_SESSION['role_name'] = $userDetails['role_name'];
        $_SESSION['site_name'] = $siteName;
        $_SESSION['site_code'] = $siteCode;
        $_SESSION['permissions'] = $permissions;
        
        // Clear temp session data
        unset($_SESSION['temp_user_id']);
        unset($_SESSION['temp_username']);
        unset($_SESSION['temp_user_sites']);
        unset($_SESSION['temp_role_code']);
        unset($_SESSION['temp_full_name']);
        unset($_SESSION['temp_permissions']);
        
        // Debug log
        error_log("Login successful - User: {$user['username']}, Role: {$userDetails['role_code']}, User ID: {$user['user_id']}");
        $_SESSION['last_activity'] = time();
        
        // Create session record (handle if table doesn't exist)
        try {
        $sessionId = session_id();
        $stmt = $db->prepare("
            INSERT INTO user_sessions (session_id, user_id, ip_address, user_agent)
            VALUES (?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE last_activity = NOW()
        ");
        $stmt->execute([
            $sessionId,
            $user['user_id'],
            $_SERVER['REMOTE_ADDR'] ?? null,
            $_SERVER['HTTP_USER_AGENT'] ?? null
        ]);
        } catch (Exception $e) {
            // Session table might not exist, log but don't fail login
            error_log("Warning: Could not create session record: " . $e->getMessage());
        }
        
        // Log audit (handle if function doesn't exist)
        if (function_exists('logAudit')) {
            try {
        logAudit('LOGIN', 'users', $user['user_id']);
            } catch (Exception $e) {
                error_log("Warning: Could not log audit: " . $e->getMessage());
            }
        }
        
        return ['success' => true, 'message' => 'Login successful.'];
        
    } catch (Exception $e) {
        error_log("Login error for username '{$username}': " . $e->getMessage());
        error_log("Login error trace: " . $e->getTraceAsString());
        return ['success' => false, 'message' => 'An error occurred during login: ' . $e->getMessage()];
    }
}

/**
 * Logout user
 */
function logout() {
    startSession();
    
    if (isset($_SESSION['user_id'])) {
        // Log audit
        logAudit('LOGOUT', 'users', $_SESSION['user_id']);
        
        // Delete session record
        try {
            $db = getDB();
            $stmt = $db->prepare("DELETE FROM user_sessions WHERE session_id = ?");
            $stmt->execute([session_id()]);
        } catch (Exception $e) {
            error_log("Error deleting session: " . $e->getMessage());
        }
    }
    
    session_destroy();
    header('Location: ' . BASE_URL . '/login.php');
    exit;
}

/**
 * Get current user ID
 */
function getCurrentUserId() {
    return isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
}

/**
 * Get current site ID
 */
function getCurrentSiteId() {
    return isset($_SESSION['site_id']) ? $_SESSION['site_id'] : null;
}

/**
 * Get role-based redirect URL
 * Redirects users to appropriate dashboard based on their role
 */
function getRoleBasedRedirect() {
    startSession();
    
    if (!isset($_SESSION['user_id'])) {
        return BASE_URL . '/login.php';
    }
    
    $roleCode = $_SESSION['role_code'] ?? '';
    
    // Role-based redirects
    switch ($roleCode) {
        case 'super_admin':
        case 'hr_admin':
            // Admin users go to dashboard
            return BASE_URL . '/dashboard.php';
            
        case 'manager':
            // Managers go to dashboard
            return BASE_URL . '/dashboard.php';
            
        case 'employee':
        default:
            // Employees go to dashboard (or employee portal if exists)
            return BASE_URL . '/dashboard.php';
    }
}

