<?php

declare(strict_types=1);

use App\Enums\Http\Api\Sort\Direction;
use App\Http\Api\Criteria\Sort\FieldCriteria;
use App\Http\Api\Criteria\Sort\RandomCriteria;
use App\Http\Api\Criteria\Sort\RelationCriteria;
use App\Http\Api\Parser\SortParser;
use App\Http\Api\Scope\GlobalScope;
use App\Http\Api\Scope\TypeScope;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Str;

uses(WithFaker::class);

test('no criteria by default', function (): void {
    $parameters = [];

    $this->assertEmpty(SortParser::parse($parameters));
});

test('parse random criteria', function (): void {
    $parameters = [
        SortParser::param() => RandomCriteria::PARAM_VALUE,
    ];

    $criteria = SortParser::parse($parameters)[0];

    $this->assertInstanceOf(RandomCriteria::class, $criteria);
});

test('parse relation criteria', function (): void {
    $parameters = [
        SortParser::param() => collect(fake()->words())->join('.'),
    ];

    $criteria = SortParser::parse($parameters)[0];

    $this->assertInstanceOf(RelationCriteria::class, $criteria);
});

test('parse field criteria', function (): void {
    $parameters = [
        SortParser::param() => fake()->word(),
    ];

    $criteria = SortParser::parse($parameters)[0];

    $this->assertInstanceOf(FieldCriteria::class, $criteria);
});

test('parse criteria field', function (): void {
    $field = fake()->word();

    $parameters = [
        SortParser::param() => $field,
    ];

    $criteria = SortParser::parse($parameters)[0];

    $this->assertEquals($field, $criteria->getField());
});

test('parse default direction', function (): void {
    $parameters = [
        SortParser::param() => fake()->word(),
    ];

    $criteria = SortParser::parse($parameters)[0];

    $this->assertTrue(
        $criteria instanceof FieldCriteria
        && $criteria->getDirection() === Direction::ASCENDING
    );
});

test('parse descending direction', function (): void {
    $field = Str::of('-')->append(fake()->word())->__toString();

    $parameters = [
        SortParser::param() => $field,
    ];

    $criteria = SortParser::parse($parameters)[0];

    $this->assertTrue(
        $criteria instanceof FieldCriteria
        && $criteria->getDirection() === Direction::DESCENDING
    );
});

test('parse global scope', function (): void {
    $parameters = [
        SortParser::param() => fake()->word(),
    ];

    $criteria = SortParser::parse($parameters)[0];

    $this->assertInstanceOf(GlobalScope::class, $criteria->getScope());
});

test('parse type scope', function (): void {
    $type = Str::singular('posts');

    $parameters = [
        SortParser::param() => [
            $type => fake()->word(),
        ],
    ];

    $criteria = SortParser::parse($parameters)[0];

    $scope = $criteria->getScope();

    $this->assertTrue($scope instanceof TypeScope && $scope->getType() === $type);
});
