<?php
// RouterTest.php
// Created: 2022-01-20
// Updated: 2023-09-08

declare(strict_types=1);

use PHPUnit\Framework\TestCase;
use Index\Routing\Route;
use Index\Routing\RouteHandler;
use Index\Routing\Router;

/**
 * @covers Router
 */
final class RouterTest extends TestCase {
    public function testRouter(): void {
        $router1 = new Router;

        $router1->get('/', function() {
            return 'get';
        });
        $router1->post('/', function() {
            return 'post';
        });
        $router1->delete('/', function() {
            return 'delete';
        });
        $router1->patch('/', function() {
            return 'patch';
        });
        $router1->put('/', function() {
            return 'put';
        });
        $router1->add('custom', '/', function() {
            return 'wacky';
        });

        $this->assertEquals(['get'], $router1->resolve('GET', '/')->runAll());
        $this->assertEquals(['wacky'], $router1->resolve('CUSTOM', '/')->runAll());

        $router1->use('/', function() {
            return 'warioware';
        });
        $router1->use('/deep', function() {
            return 'deep';
        });

        $this->assertEquals(['warioware', 'post'], $router1->resolve('POST', '/')->runAll());

        $router1->use('/user/:user/below', function(string $user) {
            return 'warioware below ' . $user;
        });

        $router1->get('/user/static', function() {
            return 'the static one';
        });
        $router1->get('/user/static/below', function() {
            return 'below the static one';
        });
        $router1->get('/user/:user', function(string $user) {
            return $user;
        });
        $router1->get('/user/:user/below', function(string $user) {
            return 'below ' . $user;
        });

        $this->assertEquals(
            ['warioware', 'below the static one'],
            $router1->resolve('GET', '/user/static/below')->runAll()
        );
        $this->assertEquals(
            ['warioware', 'warioware below flashwave', 'below flashwave'],
            $router1->resolve('GET', '/user/flashwave/below')->runAll()
        );

        $router2 = new Router;
        $router2->use('/', function() {
            return 'meow';
        });
        $router2->get('/rules', function() {
            return 'rules page';
        });
        $router2->get('/contact', function() {
            return 'contact page';
        });
        $router2->get('/25252', function() {
            return 'numeric test';
        });

        $this->assertEquals(['meow', 'rules page'], $router2->resolve('GET', '/rules')->runAll());

        $router1->merge('/info', $router2);

        $this->assertEquals(['warioware', 'meow', 'rules page'], $router1->resolve('GET', '/info/rules')->runAll());

        $this->assertEquals(['meow', 'numeric test'], $router2->resolve('GET', '/25252')->runAll());

        $router3 = new Router;
        $router3->get('/static', function() {
            return 'wrong';
        });
        $router3->get('/static/0', function() {
            return 'correct';
        });
        $router3->get('/variable', function() {
            return 'wrong';
        });
        $router3->get('/variable/:num', function(string $num) {
            return $num === '0' ? 'correct' : 'VERY wrong';
        });

        $this->assertEquals('correct', $router3->resolve('GET', '/static/0')->run());
        $this->assertEquals('correct', $router3->resolve('GET', '/variable/0')->run());
    }

    public function testAttribute(): void {
        $router = new Router;
        $handler = new class extends RouteHandler {
            #[Route('GET', '/')]
            public function getIndex() {
                return 'index';
            }

            #[Route('POST', '/avatar')]
            public function postAvatar() {
                return 'avatar';
            }

            #[Route('PUT', '/static')]
            public static function putStatic() {
                return 'static';
            }

            #[Route('GET', '/meow')]
            #[Route('POST', '/meow')]
            public function multiple() {
                return 'meow';
            }

            #[Route('/mw')]
            public function useMw() {
                return 'this intercepts';
            }

            #[Route('GET', '/mw')]
            public function getMw() {
                return 'this is intercepted';
            }

            public function hasNoAttr() {
                return 'not a route';
            }
        };

        $router->register($handler);
        $this->assertEquals('index', $router->resolve('GET', '/')->run());
        $this->assertEquals('avatar', $router->resolve('POST', '/avatar')->run());
        $this->assertEquals('static', $router->resolve('PUT', '/static')->run());
        $this->assertEquals('meow', $router->resolve('GET', '/meow')->run());
        $this->assertEquals('meow', $router->resolve('POST', '/meow')->run());
        $this->assertEquals('this intercepts', $router->resolve('GET', '/mw')->run());
    }
}