<?php

namespace SilverStripe\Control\Tests\Middleware;

use SilverStripe\Control\Middleware\RateLimitMiddleware;
use SilverStripe\Control\Middleware\RequestHandlerMiddlewareAdapter;
use SilverStripe\Control\Tests\Middleware\Control\TestController;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\ORM\FieldType\DBDatetime;

class RateLimitMiddlewareTest extends FunctionalTest
{

    protected static $extra_controllers = [
        TestController::class,
    ];

    protected function setUp()
    {
        parent::setUp();
        DBDatetime::set_mock_now('2017-09-27 00:00:00');
        Config::modify()->set(Injector::class, 'TestRateLimitMiddleware', [
            'class' => RateLimitMiddleware::class,
            'properties' => [
                'ExtraKey' => 'test',
                'MaxAttempts' => 2,
                'Decay' => 1,
            ],
        ]);
        Config::modify()->set(Injector::class, 'RateLimitTestController', [
            'class' => RequestHandlerMiddlewareAdapter::class,
            'properties' => [
                'RequestHandler' => '%$' . TestController::class,
                'Middlewares' => [
                    '%$TestRateLimitMiddleware'
                ],
            ],
        ]);
    }

    protected function getExtraRoutes()
    {
        $rules = parent::getExtraRoutes();
        $rules['TestController//$Action/$ID/$OtherID'] = '%$RateLimitTestController';
        return $rules;
    }

    public function testRequest()
    {
        $response = $this->get('TestController');
        $this->assertFalse($response->isError());
        $this->assertEquals(2, $response->getHeader('X-RateLimit-Limit'));
        $this->assertEquals(1, $response->getHeader('X-RateLimit-Remaining'));
        $this->assertEquals(DBDatetime::now()->getTimestamp() + 60, $response->getHeader('X-RateLimit-Reset'));
        $this->assertEquals('Success', $response->getBody());
        $response = $this->get('TestController');
        $this->assertFalse($response->isError());
        $this->assertEquals(0, $response->getHeader('X-RateLimit-Remaining'));
        $response = $this->get('TestController');
        $this->assertTrue($response->isError());
        $this->assertEquals(429, $response->getStatusCode());
        $this->assertEquals(60, $response->getHeader('retry-after'));
        $this->assertNotEquals('Success', $response->getBody());
    }
}