<?php

declare(strict_types=1);

namespace Rowbot\URL\Tests;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Rowbot\URL\BasicURLParser;
use Rowbot\URL\Component\Host\HostParser;
use Rowbot\URL\Component\OpaqueOrigin;
use Rowbot\URL\Component\TupleOrigin;
use Rowbot\URL\Origin;
use Rowbot\URL\ParserContext;
use Rowbot\URL\String\StringBuffer;
use Rowbot\URL\String\Utf8String;
use Rowbot\URL\String\Utf8StringIterator;
use Rowbot\URL\URLRecord;

class OriginTest extends TestCase
{
    public static function originProvider(): array
    {
        $hostParser = new HostParser();
        $context = new ParserContext(
            new Utf8String(''),
            new Utf8StringIterator(''),
            new StringBuffer(''),
            new URLRecord(),
            null,
            null,
            null,
            null
        );
        $tuple = new TupleOrigin(
            'https',
            $hostParser->parse($context, new Utf8String('example.org'), false),
            null,
            null
        );
        $tupleDomain = new TupleOrigin(
            'https',
            $hostParser->parse($context, new Utf8String('example.org'), false),
            null,
            'example.org'
        );
        $opaque = new OpaqueOrigin();
        $urlParser = new BasicURLParser();

        return [
            [
                $tuple,
                new TupleOrigin(
                    'https',
                    $hostParser->parse($context, new Utf8String('example.org'), false),
                    null,
                    null
                ),
                'isSameOrigin' => true,
                'isSameOriginDomain' => true,
            ],
            [
                new TupleOrigin('https', $hostParser->parse($context, new Utf8String('example.org'), false), 314, null),
                new TupleOrigin('https', $hostParser->parse($context, new Utf8String('example.org'), false), 420, null),
                'isSameOrigin' => false,
                'isSameOriginDomain' => false,
            ],
            [
                new TupleOrigin(
                    'https',
                    $hostParser->parse($context, new Utf8String('example.org'), false),
                    314,
                    'example.org'
                ),
                new TupleOrigin(
                    'https',
                    $hostParser->parse($context, new Utf8String('example.org'), false),
                    420,
                    'example.org'
                ),
                'isSameOrigin' => false,
                'isSameOriginDomain' => true,
            ],
            [
                new TupleOrigin(
                    'https',
                    $hostParser->parse($context, new Utf8String('example.org'), false),
                    null,
                    null
                ),
                new TupleOrigin(
                    'https',
                    $hostParser->parse($context, new Utf8String('example.org'), false),
                    null,
                    'example.org'
                ),
                'isSameOrigin' => true,
                'isSameOriginDomain' => false,
            ],
            [
                new TupleOrigin(
                    'https',
                    $hostParser->parse($context, new Utf8String('example.org'), false),
                    null,
                    'example.org'
                ),
                new TupleOrigin(
                    'http',
                    $hostParser->parse($context, new Utf8String('example.org'), false),
                    null,
                    'example.org'
                ),
                'isSameOrigin' => false,
                'isSameOriginDomain' => false,
            ],
            [
                new TupleOrigin('https', $hostParser->parse($context, new Utf8String('127.0.0.1'), false), null, null),
                new TupleOrigin('https', $hostParser->parse($context, new Utf8String('1.1.1.1'), false), null, null),
                'isSameOrigin' => false,
                'isSameOriginDomain' => false,
            ],
            [
                new TupleOrigin('https', $hostParser->parse($context, new Utf8String('[::1]'), false), null, null),
                new TupleOrigin('https', $hostParser->parse($context, new Utf8String('[1::1]'), false), null, null),
                'isSameOrigin' => false,
                'isSameOriginDomain' => false,
            ],
            [
                $urlParser->parse(new Utf8String('blob:https://foo.com'))->getOrigin(),
                $urlParser->parse(new Utf8String('https://foo.com'))->getOrigin(),
                'isSameOrigin' => true,
                'isSameOriginDomain' => true,
            ],
            [
                $tuple,
                $tuple,
                'isSameOrigin' => true,
                'isSameOriginDomain' => true,
            ],
            [
                $tuple,
                $tupleDomain,
                'isSameOrigin' => true,
                'isSameOriginDomain' => false,
            ],
            [
                $opaque,
                new OpaqueOrigin(),
                'isSameOrigin' => false,
                'isSameOriginDomain' => false,
            ],
            [
                $opaque,
                $opaque,
                'isSameOrigin' => true,
                'isSameOriginDomain' => true,
            ],
            [
                $tuple,
                $opaque,
                'isSameOrigin' => false,
                'isSameOriginDomain' => false,
            ],
        ];
    }

    #[DataProvider('originProvider')]
    public function testSameOriginConcept(
        Origin $originA,
        Origin $originB,
        bool $isSameOrigin,
        bool $isSameOriginDomain
    ): void {
        self::assertSame($isSameOrigin, $originA->isSameOrigin($originB));
        self::assertSame($isSameOriginDomain, $originA->isSameOriginDomain($originB));
    }

    public function testEffectiveDomainConcept(): void
    {
        $origin = new OpaqueOrigin();
        self::assertTrue($origin->isOpaque());
        self::assertNull($origin->getEffectiveDomain());

        $parser = new BasicURLParser();
        $record = $parser->parse(new Utf8String('blob:https://foo.com'));
        $origin = $record->getOrigin();
        self::assertFalse($origin->isOpaque());
        self::assertNotNull($origin->getEffectiveDomain());
        self::assertSame('foo.com', $origin->getEffectiveDomain());

        $hostParser = new HostParser();
        $context = new ParserContext(
            new Utf8String(''),
            new Utf8StringIterator(''),
            new StringBuffer(''),
            new URLRecord(),
            null,
            null,
            null,
            null
        );
        $origin = new TupleOrigin(
            'https',
            $hostParser->parse($context, new Utf8String('example.org'), false),
            314,
            'example.org'
        );
        self::assertFalse($origin->isOpaque());
        self::assertNotNull($origin->getEffectiveDomain());
        self::assertSame('example.org', $origin->getEffectiveDomain());
    }
}
