<?php

namespace MintyPHP\Tests\Service\Settings;

use MintyPHP\Repository\Settings\SettingRepositoryInterface;
use MintyPHP\Service\Settings\SettingsMetadataGateway;
use MintyPHP\Service\Settings\SettingsSessionGateway;
use PHPUnit\Framework\TestCase;

class SettingsSessionGatewayTest extends TestCase
{
    public function testGetSessionIdleTimeoutMinutesReturnsFallbackWhenNotSet(): void
    {
        $gateway = $this->createGateway(null);
        $this->assertSame(30, $gateway->getSessionIdleTimeoutMinutes());
    }

    public function testGetSessionAbsoluteTimeoutHoursReturnsFallbackWhenNotSet(): void
    {
        $gateway = $this->createGateway(null);
        $this->assertSame(8, $gateway->getSessionAbsoluteTimeoutHours());
    }

    public function testGetSessionIdleTimeoutMinutesReturnsStoredValue(): void
    {
        $gateway = $this->createGateway('15', 'session_idle_timeout_minutes');
        $this->assertSame(15, $gateway->getSessionIdleTimeoutMinutes());
    }

    public function testGetSessionAbsoluteTimeoutHoursReturnsStoredValue(): void
    {
        $gateway = $this->createGateway('12', 'session_absolute_timeout_hours');
        $this->assertSame(12, $gateway->getSessionAbsoluteTimeoutHours());
    }

    public function testGetSessionIdleTimeoutMinutesReturnsFallbackForOutOfBoundsValue(): void
    {
        $gateway = $this->createGateway('2', 'session_idle_timeout_minutes');
        $this->assertSame(30, $gateway->getSessionIdleTimeoutMinutes());
    }

    public function testGetSessionAbsoluteTimeoutHoursReturnsFallbackForOutOfBoundsValue(): void
    {
        $gateway = $this->createGateway('100', 'session_absolute_timeout_hours');
        $this->assertSame(8, $gateway->getSessionAbsoluteTimeoutHours());
    }

    public function testSetSessionIdleTimeoutMinutesRejectsBelowMinimum(): void
    {
        $settings = $this->createMock(SettingRepositoryInterface::class);
        $settings->expects($this->never())->method('set');
        $gateway = new SettingsSessionGateway(new SettingsMetadataGateway($settings));
        $this->assertFalse($gateway->setSessionIdleTimeoutMinutes(2));
    }

    public function testSetSessionIdleTimeoutMinutesRejectsAboveMaximum(): void
    {
        $settings = $this->createMock(SettingRepositoryInterface::class);
        $settings->expects($this->never())->method('set');
        $gateway = new SettingsSessionGateway(new SettingsMetadataGateway($settings));
        $this->assertFalse($gateway->setSessionIdleTimeoutMinutes(2000));
    }

    public function testSetSessionAbsoluteTimeoutHoursRejectsZero(): void
    {
        $settings = $this->createMock(SettingRepositoryInterface::class);
        $settings->expects($this->never())->method('set');
        $gateway = new SettingsSessionGateway(new SettingsMetadataGateway($settings));
        $this->assertFalse($gateway->setSessionAbsoluteTimeoutHours(0));
    }

    public function testGetSessionIdleTimeoutSecondsConvertsCorrectly(): void
    {
        $gateway = $this->createGateway('15', 'session_idle_timeout_minutes');
        $this->assertSame(900, $gateway->getSessionIdleTimeoutSeconds());
    }

    public function testGetSessionAbsoluteTimeoutSecondsConvertsCorrectly(): void
    {
        $gateway = $this->createGateway('4', 'session_absolute_timeout_hours');
        $this->assertSame(14400, $gateway->getSessionAbsoluteTimeoutSeconds());
    }

    private function createGateway(?string $returnValue, string $forKey = ''): SettingsSessionGateway
    {
        $settings = $this->createMock(SettingRepositoryInterface::class);
        $settings->method('getValue')->willReturnCallback(
            static function (string $key) use ($returnValue, $forKey): ?string {
                if ($forKey !== '' && $key === $forKey) {
                    return $returnValue;
                }
                return $returnValue !== null && $forKey === '' ? $returnValue : null;
            }
        );

        return new SettingsSessionGateway(new SettingsMetadataGateway($settings));
    }
}
