<?php
namespace {
    if (!defined('WD')) { define('WD', dirname(__DIR__, 2)); }

    // Setup request context
    global $response, $router, $DEBUG;
    $DEBUG = true;
    $_SERVER['REQUEST_URI'] = '/auth/passkey/challenge';
    $_SERVER['REQUEST_METHOD'] = 'POST';
}

// Mock response class in classes namespace
namespace classes {
    class MockExitException extends \Error {}

    class response {
        public static $last_success = null;
        public static $last_error = null;
        public static $last_status = null;
        public static $request_parameters = [];

        public static function reset() {
            self::$last_success = null;
            self::$last_error = null;
            self::$last_status = null;
            self::$request_parameters = [];
        }

        public function success($data, $status = 200) {
            self::$last_success = $data;
            self::$last_status = $status;
            throw new MockExitException("SUCCESS_EXIT");
        }

        public function error($data, $status = 400) {
            self::$last_error = $data;
            self::$last_status = $status;
            throw new MockExitException("ERROR_EXIT");
        }

        public function getRequestParameter($key) {
            return self::$request_parameters[$key] ?? null;
        }

        public function isRequestParameterSet($key) {
            return array_key_exists($key, self::$request_parameters);
        }
    }

    class recaptcha {
        public static $mock_valid = true;
        public function validate($resp) { return self::$mock_valid; }
    }
}

// Mock objects needed by the route
namespace objects {
    class logs_o { public function add($a,$b,$c,$d,$e,$f) {} }
    class tokens_o {
        public static $created = [];
        public function create($user_id, $token, $type = 'AUTH_TOKEN') { self::$created[] = compact('user_id','token','type'); }
    }

    class MockUserObj {
        public $id;
        public function __construct($id) { $this->id = $id; }
        public function exists() { return $this->id > 0; }
    }

    class users_o {
        public static $existing_numbers = [];
        public function getUserByCustomerNumber($num) {
            if (in_array((int)$num, self::$existing_numbers, true)) { return new MockUserObj(42); }
            return new MockUserObj(0);
        }
    }

    class passkeys_o {
        public $where;
        public function setAdditionalWhereClause($w) { $this->where = $w; }
        public function listObjectsWithPaginationIfSet($parser) {
            $items = [
                ['credential_id' => 'cred_abcd', 'transports' => json_encode(['internal'])],
                ['credential_id' => 'cred_efgh', 'transports' => json_encode(['hybrid','usb'])],
            ];
            $out = [];
            foreach ($items as $o) { $out[] = $parser($o); }
            return $out;
        }
    }
}

// Provide a minimal router mock and run the route
namespace {
    class MockRouter {
        public $routes = [];
        public function add($route, $method, $callback, $permissions) { $this->routes[$method][$route] = $callback; }
    }

    $router = new MockRouter();
    $response = new \classes\response();

    require_once WD . '/traits/route_t.php';
    require_once WD . '/routes/authRoute.php';

    use routes\authRoute;

    function ok($m){ echo "\033[32m✔ $m\033[0m\n"; }
    function fail($m){ echo "\033[31m✖ $m\033[0m\n"; }

    $authRoute = new authRoute();
    $authRoute->run();

    if (!isset($router->routes['POST']['/auth/passkey/challenge'])) {
        die("Route /auth/passkey/challenge not found\n");
    }

    $callback = $router->routes['POST']['/auth/passkey/challenge'];

    // Test case: valid request for existing user
    \classes\response::reset();
    \classes\recaptcha::$mock_valid = true;
    \objects\users_o::$existing_numbers = [12345];
    \classes\response::$request_parameters = [
        'customer_number' => 12345,
        'g_recaptcha_response' => 'valid'
    ];

    try {
        $callback();
    } catch (\classes\MockExitException $e) {
        if ($e->getMessage() !== 'SUCCESS_EXIT') { fail('Expected SUCCESS_EXIT'); exit(1); }
    }

    $data = \classes\response::$last_success;
    if (!is_array($data)) { fail('Response should be array'); exit(1); }
    if (!isset($data['challenge_token']) || !is_string($data['challenge_token'])) { fail('Missing challenge_token'); exit(1); }
    if (!isset($data['publicKey']) || !is_array($data['publicKey'])) { fail('Missing publicKey'); exit(1); }
    $pk = $data['publicKey'];
    if (!isset($pk['challenge']) || !is_string($pk['challenge'])) { fail('Missing publicKey.challenge'); exit(1); }
    if (!isset($pk['rpId']) || $pk['rpId'] !== 'truckwash.io') { fail('Missing or incorrect publicKey.rpId: ' . ($pk['rpId'] ?? 'null')); exit(1); }
    if (!isset($pk['allowCredentials']) || !is_array($pk['allowCredentials'])) { fail('Missing publicKey.allowCredentials'); exit(1); }
    if (count($pk['allowCredentials']) !== 2) { fail('Expected 2 allowCredentials'); exit(1); }
    ok('Passkey challenge returns expected structure for existing user');

    // Test case: valid request for non-existing user → allowCredentials may be empty but still returns challenge
    \classes\response::reset();
    \objects\users_o::$existing_numbers = [];
    \classes\response::$request_parameters = [
        'customer_number' => 99999,
        'g_recaptcha_response' => 'valid'
    ];

    try {
        $callback();
    } catch (\classes\MockExitException $e) {
        if ($e->getMessage() !== 'SUCCESS_EXIT') { fail('Expected SUCCESS_EXIT for non-existing user'); exit(1); }
    }

    $data = \classes\response::$last_success;
    if (!isset($data['publicKey']['allowCredentials'])) { fail('Missing allowCredentials for non-existing'); exit(1); }
    ok('Passkey challenge works for non-existing user (empty allowCredentials)');

    // Test case: localhost support
    \classes\response::reset();
    \classes\recaptcha::$mock_valid = true;
    \objects\users_o::$existing_numbers = [12345];
    \classes\response::$request_parameters = [
        'customer_number' => 12345,
        'g_recaptcha_response' => 'valid'
    ];
    $_SERVER['HTTP_HOST'] = 'localhost:8080';

    try {
        $callback();
    } catch (\classes\MockExitException $e) {
        if ($e->getMessage() !== 'SUCCESS_EXIT') { fail('Expected SUCCESS_EXIT for localhost'); exit(1); }
    }

    $data = \classes\response::$last_success;
    if ($data['publicKey']['rpId'] !== 'localhost') { fail('Expected rpId localhost, got: ' . $data['publicKey']['rpId']); exit(1); }
    ok('Passkey challenge returns rpId localhost when host is localhost');

    echo "PasskeyChallengeTest completed.\n";
}
