<?php
/**
 * Authentication API
 * Handles login, logout, session management, and RBAC
 */

require_once __DIR__ . '/../config/config.php';

class AuthService {
    private $db;

    public function __construct() {
        $this->db = Database::getInstance()->getConnection();
    }

    /**
     * Login user with username and password
     */
    public function login($username, $password) {
        $stmt = $this->db->prepare("
            SELECT id, username, password_hash, email, full_name, locale, timezone,
                   status, twofa_enabled, twofa_secret
            FROM users
            WHERE username = ? AND status = 'active'
        ");
        $stmt->execute([$username]);
        $user = $stmt->fetch();

        if (!$user) {
            $this->logFailedLogin($username);
            return ['success' => false, 'message' => 'Invalid credentials'];
        }

        // Check if account is locked
        if ($this->isAccountLocked($username)) {
            return ['success' => false, 'message' => 'Account temporarily locked due to too many failed attempts'];
        }

        // Verify password
        if (!password_verify($password, $user['password_hash'])) {
            $this->logFailedLogin($username);
            return ['success' => false, 'message' => 'Invalid credentials'];
        }

        // Check 2FA if enabled
        if ($user['twofa_enabled']) {
            return [
                'success' => false,
                'requires_2fa' => true,
                'user_id' => $user['id']
            ];
        }

        // Create session
        $sessionId = $this->createSession($user);

        // Update last login
        $this->updateLastLogin($user['id']);

        // Clear failed login attempts
        $this->clearFailedLogins($username);

        return [
            'success' => true,
            'session_id' => $sessionId,
            'user' => [
                'id' => $user['id'],
                'username' => $user['username'],
                'full_name' => $user['full_name'],
                'email' => $user['email'],
                'locale' => $user['locale'],
                'timezone' => $user['timezone']
            ]
        ];
    }

    /**
     * Verify 2FA code
     */
    public function verify2FA($userId, $code) {
        // TODO: Implement TOTP verification
        // This is a placeholder for 2FA implementation
        return ['success' => true, 'message' => '2FA not yet implemented'];
    }

    /**
     * Create user session
     */
    private function createSession($user) {
        session_start();
        $sessionId = session_id();

        $_SESSION['user_id'] = $user['id'];
        $_SESSION['username'] = $user['username'];
        $_SESSION['locale'] = $user['locale'];
        $_SESSION['timezone'] = $user['timezone'];
        $_SESSION['login_time'] = time();
        $_SESSION['last_activity'] = time();

        // Store session in database
        $stmt = $this->db->prepare("
            INSERT INTO sessions (id, user_id, ip_address, user_agent, payload, last_activity)
            VALUES (?, ?, ?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE
                user_id = VALUES(user_id),
                ip_address = VALUES(ip_address),
                user_agent = VALUES(user_agent),
                payload = VALUES(payload),
                last_activity = VALUES(last_activity)
        ");

        $stmt->execute([
            $sessionId,
            $user['id'],
            $_SERVER['REMOTE_ADDR'] ?? null,
            $_SERVER['HTTP_USER_AGENT'] ?? null,
            json_encode($_SESSION),
            time()
        ]);

        return $sessionId;
    }

    /**
     * Logout user
     */
    public function logout() {
        session_start();
        $sessionId = session_id();

        // Remove session from database
        $stmt = $this->db->prepare("DELETE FROM sessions WHERE id = ?");
        $stmt->execute([$sessionId]);

        // Destroy PHP session
        session_unset();
        session_destroy();

        return ['success' => true, 'message' => 'Logged out successfully'];
    }

    /**
     * Get current user from session
     */
    public function getCurrentUser() {
        if (!isset($_SESSION)) {
            session_start();
        }

        if (!isset($_SESSION['user_id'])) {
            return null;
        }

        // Check session timeout
        if (isset($_SESSION['last_activity'])) {
            $inactive = time() - $_SESSION['last_activity'];
            if ($inactive > SESSION_TIMEOUT) {
                $this->logout();
                return null;
            }
        }

        // Update last activity
        $_SESSION['last_activity'] = time();

        $stmt = $this->db->prepare("
            SELECT id, username, email, full_name, locale, timezone, status
            FROM users
            WHERE id = ? AND status = 'active'
        ");
        $stmt->execute([$_SESSION['user_id']]);
        return $stmt->fetch();
    }

    /**
     * Get user permissions
     */
    public function getUserPermissions($userId) {
        $stmt = $this->db->prepare("
            SELECT DISTINCT pr.code as program_code, p.action
            FROM users u
            LEFT JOIN user_roles ur ON u.id = ur.user_id
            LEFT JOIN role_permissions rp ON ur.role_id = rp.role_id
            LEFT JOIN permissions p ON rp.permission_id = p.id
            LEFT JOIN programs pr ON p.program_id = pr.id
            WHERE u.id = ? AND rp.allow = 1
            UNION
            SELECT DISTINCT pr.code as program_code, p.action
            FROM user_permissions up
            INNER JOIN permissions p ON up.permission_id = p.id
            INNER JOIN programs pr ON p.program_id = pr.id
            WHERE up.user_id = ? AND up.allow = 1
        ");
        $stmt->execute([$userId, $userId]);
        $results = $stmt->fetchAll();

        $permissions = [];
        foreach ($results as $row) {
            if (!isset($permissions[$row['program_code']])) {
                $permissions[$row['program_code']] = [];
            }
            $permissions[$row['program_code']][] = $row['action'];
        }

        return $permissions;
    }

    /**
     * Check if user has specific permission
     */
    public function hasPermission($userId, $programCode, $action) {
        $permissions = $this->getUserPermissions($userId);
        return isset($permissions[$programCode]) && in_array($action, $permissions[$programCode]);
    }

    /**
     * Log failed login attempt
     */
    private function logFailedLogin($username) {
        $key = 'failed_login_' . $username;
        $attempts = apcu_exists($key) ? apcu_fetch($key) : 0;
        apcu_store($key, $attempts + 1, LOGIN_LOCKOUT_TIME);
    }

    /**
     * Check if account is locked
     */
    private function isAccountLocked($username) {
        $key = 'failed_login_' . $username;
        if (apcu_exists($key)) {
            $attempts = apcu_fetch($key);
            return $attempts >= LOGIN_MAX_ATTEMPTS;
        }
        return false;
    }

    /**
     * Clear failed login attempts
     */
    private function clearFailedLogins($username) {
        $key = 'failed_login_' . $username;
        apcu_delete($key);
    }

    /**
     * Update last login timestamp
     */
    private function updateLastLogin($userId) {
        $stmt = $this->db->prepare("
            UPDATE users
            SET last_login_at = NOW(), last_login_ip = ?
            WHERE id = ?
        ");
        $stmt->execute([$_SERVER['REMOTE_ADDR'] ?? null, $userId]);
    }

    /**
     * Log audit event
     */
    public function logAudit($action, $targetType = null, $targetId = null, $diff = null) {
        $user = $this->getCurrentUser();
        $userId = $user ? $user['id'] : null;

        $stmt = $this->db->prepare("
            INSERT INTO audit_logs (actor_user_id, action, target_type, target_id, diff_json, ip, user_agent)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        ");

        $stmt->execute([
            $userId,
            $action,
            $targetType,
            $targetId,
            $diff ? json_encode($diff) : null,
            $_SERVER['REMOTE_ADDR'] ?? null,
            $_SERVER['HTTP_USER_AGENT'] ?? null
        ]);
    }
}

// Authentication middleware
function requireAuth() {
    $auth = new AuthService();
    $user = $auth->getCurrentUser();

    if (!$user) {
        Response::error('Authentication required', 401);
        return false;
    }

    // Store user in global variable for request
    $GLOBALS['current_user'] = $user;
    return true;
}

// Permission check middleware factory
function requirePermission($programCode, $action) {
    return function() use ($programCode, $action) {
        if (!requireAuth()) {
            return false;
        }

        $auth = new AuthService();
        $user = $GLOBALS['current_user'];

        if (!$auth->hasPermission($user['id'], $programCode, $action)) {
            Response::error('Permission denied', 403);
            return false;
        }

        return true;
    };
}
