<?php
/**
 * Authentication Middleware
 * JWT Token handling for API security
 */

class Auth {
    private static $config = null;

    /**
     * Load JWT configuration securely
     */
    private static function loadConfig() {
        if (self::$config === null) {
            // Try to load from environment variables first (most secure)
            self::$config = [
                'secret' => getenv('JWT_SECRET') ?: self::getConfigValue('JWT_SECRET'),
                'algorithm' => getenv('JWT_ALGORITHM') ?: self::getConfigValue('JWT_ALGORITHM', 'HS256'),
                'expiry' => getenv('JWT_EXPIRY') ?: self::getConfigValue('JWT_EXPIRY', 24 * 60 * 60),
                'issuer' => getenv('JWT_ISSUER') ?: self::getConfigValue('JWT_ISSUER', 'bus_checkin_api'),
                'refresh_expiry' => getenv('JWT_REFRESH_EXPIRY') ?: self::getConfigValue('JWT_REFRESH_EXPIRY', 30 * 24 * 60 * 60)
            ];
        }
        return self::$config;
    }

    /**
     * Get configuration value from secure config file
     */
    private static function getConfigValue($key, $default = null) {
        $configFile = __DIR__ . '/../config/jwt_secure.php';

        if (file_exists($configFile)) {
            $config = include $configFile;
            return $config[$key] ?? $default;
        }

        return $default;
    }

    /**
     * Generate JWT token
     */
    public static function generateToken($user_data) {
        $config = self::loadConfig();

        $header = json_encode(['typ' => 'JWT', 'alg' => $config['algorithm']]);
        $header_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));

        $payload = json_encode([
            'iss' => $config['issuer'],
            'iat' => time(),
            'exp' => time() + $config['expiry'],
            'user' => $user_data
        ]);
        $payload_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));

        $signature = hash_hmac('sha256', $header_encoded . "." . $payload_encoded, $config['secret'], true);
        $signature_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

        return $header_encoded . "." . $payload_encoded . "." . $signature_encoded;
    }

    /**
     * Verify JWT token
     */
    public static function verifyToken($token = null) {
        if ($token === null) {
            $token = self::getTokenFromHeader();
        }

        if (!$token) {
            return false;
        }

        $token_parts = explode('.', $token);
        if (count($token_parts) !== 3) {
            return false;
        }

        $config = self::loadConfig();
        $header = $token_parts[0];
        $payload = $token_parts[1];
        $signature = $token_parts[2];

        // Verify signature
        $expected_signature = hash_hmac('sha256', $header . "." . $payload, $config['secret'], true);
        $expected_signature_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($expected_signature));

        if (!hash_equals($signature, $expected_signature_encoded)) {
            return false;
        }

        // Decode payload and check expiration
        $payload_decoded = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $payload)), true);

        if (!$payload_decoded || !isset($payload_decoded['exp']) || $payload_decoded['exp'] < time()) {
            return false;
        }

        // Additional security checks
        if (!isset($payload_decoded['iss']) || $payload_decoded['iss'] !== $config['issuer']) {
            return false;
        }

        return $payload_decoded;
    }

    /**
     * Get token from Authorization header or GET parameter
     */
    public static function getTokenFromHeader() {
        // FIRST: Try GET parameter (cPanel compatibility)
        if (isset($_GET['token']) && !empty($_GET['token'])) {
            error_log("Token found in GET parameter");
            return $_GET['token'];
        }

        // SECOND: Try Authorization header methods
        // Debug: Log all server variables that might contain auth
        error_log("Checking SERVER vars for auth:");
        foreach ($_SERVER as $key => $value) {
            if (stripos($key, 'auth') !== false || stripos($key, 'authorization') !== false) {
                error_log("$key: $value");
            }
        }

        // Try direct $_SERVER access first (most reliable for cPanel)
        $auth_header = $_SERVER['HTTP_AUTHORIZATION'] ??
                      $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ??
                      $_SERVER['Authorization'] ??
                      $_SERVER['authorization'] ?? '';

        // If still empty, try getallheaders
        if (empty($auth_header) && function_exists('getallheaders')) {
            $headers = getallheaders();
            $auth_header = $headers['Authorization'] ??
                          $headers['authorization'] ??
                          $headers['Authorisation'] ?? '';
        }

        // If still empty, try parsing $_SERVER HTTP_* variables
        if (empty($auth_header)) {
            foreach ($_SERVER as $key => $value) {
                if (substr($key, 0, 5) === 'HTTP_') {
                    $header_name = str_replace('_', '-', substr($key, 5));
                    if (strtolower($header_name) === 'authorization') {
                        $auth_header = $value;
                        break;
                    }
                }
            }
        }

        error_log("Final auth_header: " . substr($auth_header, 0, 50) . "...");

        if (preg_match('/Bearer\s+(.*)$/i', $auth_header, $matches)) {
            return $matches[1];
        }

        return null;
    }

    /**
     * Get current user from token
     */
    public static function getCurrentUser() {
        $payload = self::verifyToken();
        return $payload ? $payload['user'] : null;
    }

    /**
     * Require authentication for endpoint
     */
    public static function requireAuth() {
        $user = self::getCurrentUser();
        if (!$user) {
            // Debug: Log authentication failure
            error_log("Auth failed - Token: " . self::getTokenFromHeader());
            error_log("Auth failed - Headers: " . json_encode(getallheaders()));

            http_response_code(401);
            echo json_encode([
                'success' => false,
                'message' => 'Authentication required',
                'debug' => [
                    'token_received' => self::getTokenFromHeader() ? 'yes' : 'no',
                    'headers_available' => function_exists('getallheaders') ? 'yes' : 'no'
                ]
            ]);
            exit();
        }
        return $user;
    }

    /**
     * Require admin role
     */
    public static function requireAdmin() {
        $user = self::requireAuth();
        if ($user['role'] !== 'Admin') {
            http_response_code(403);
            echo json_encode([
                'success' => false,
                'message' => 'Admin access required'
            ]);
            exit();
        }
        return $user;
    }

    /**
     * Require agent role
     */
    public static function requireAgent() {
        $user = self::requireAuth();
        if ($user['role'] !== 'Agent') {
            http_response_code(403);
            echo json_encode([
                'success' => false,
                'message' => 'Agent access required'
            ]);
            exit();
        }
        return $user;
    }

    /**
     * Get request body as JSON
     */
    public static function getRequestBody() {
        return json_decode(file_get_contents('php://input'), true);
    }

    /**
     * Send JSON response
     */
    public static function sendResponse($data, $status_code = 200) {
        http_response_code($status_code);
        echo json_encode($data);
        exit();
    }

    /**
     * Send error response
     */
    public static function sendError($message, $status_code = 400, $errors = null) {
        $response = [
            'success' => false,
            'message' => $message
        ];

        if ($errors) {
            $response['errors'] = $errors;
        }

        self::sendResponse($response, $status_code);
    }

    /**
     * Send success response
     */
    public static function sendSuccess($data = null, $message = 'Success', $status_code = 200) {
        $response = [
            'success' => true,
            'message' => $message
        ];

        if ($data !== null) {
            $response['data'] = $data;
        }

        self::sendResponse($response, $status_code);
    }
}
?>
