<?php

namespace Appwrite;

use PHPUnit\Framework\TestCase;

final class BasicFilterQueryTest {
    public $description;
    public $value;
    public $expectedValues;

    public function __construct(string $description, mixed $value, string $expectedValues) {
        $this->description = $description;
        $this->value = $value;
        $this->expectedValues = $expectedValues;
    }
}

final class QueryTest extends TestCase {
    /**
     * @var BasicFilterQueryTest[] $tests
     */
    private $tests;

    function __construct(string $name)
    {
        parent::__construct($name);
        $this->tests = array(
            new BasicFilterQueryTest('with a string', 's', '["s"]'),
            new BasicFilterQueryTest('with a integer', 1, '[1]'),
            new BasicFilterQueryTest('with a double', 1.2, '[1.2]'),
            new BasicFilterQueryTest('with a whole number double', 1.0, '[1]'),
            new BasicFilterQueryTest('with a bool', false, '[false]'),
            new BasicFilterQueryTest('with a list', ['a', 'b', 'c'], '["a","b","c"]'),
        );
    }

    public function testBasicFilterEqual(): void {
        foreach($this->tests as $test) {
            $this->assertSame(
                "equal(\"attr\", $test->expectedValues)",
                Query::equal('attr', $test->value),
                $test->description,
            );
        }
    }

    public function testBasicFilterNotEqual(): void {
        foreach($this->tests as $test) {
            $this->assertSame(
                "notEqual(\"attr\", $test->expectedValues)",
                Query::notEqual('attr', $test->value),
                $test->description,
            );
        }
    }

    public function testBasicFilterLessThan(): void {
        foreach($this->tests as $test) {
            $this->assertSame(
                "lessThan(\"attr\", $test->expectedValues)",
                Query::lessThan('attr', $test->value),
                $test->description,
            );
        }
    }

    public function testBasicFilterLessThanEqual(): void {
        foreach($this->tests as $test) {
            $this->assertSame(
                "lessThanEqual(\"attr\", $test->expectedValues)",
                Query::lessThanEqual('attr', $test->value),
                $test->description,
            );
        }
    }

    public function testBasicFilterGreaterThan(): void {
        foreach($this->tests as $test) {
            $this->assertSame(
                "greaterThan(\"attr\", $test->expectedValues)",
                Query::greaterThan('attr', $test->value),
                $test->description,
            );
        }
    }

    public function testBasicFilterGreaterThanEqual(): void {
        foreach($this->tests as $test) {
            $this->assertSame(
                "greaterThanEqual(\"attr\", $test->expectedValues)",
                Query::greaterThanEqual('attr', $test->value),
                $test->description,
            );
        }
    }

    public function testSearch(): void {
        $this->assertSame('search("attr", ["keyword1 keyword2"])', Query::search('attr', 'keyword1 keyword2'));
    }

    public function testIsNull(): void {
        $this->assertSame('isNull("attr")', Query::isNull('attr'));
    }

    public function testIsNotNull(): void {
        $this->assertSame('isNotNull("attr")', Query::isNotNull('attr'));
    }

    public function testBetweenWithIntegers(): void {
        $this->assertSame('between("attr", 1, 2)', Query::between('attr', 1, 2));
    }

    public function testBetweenWithDoubles(): void {
        $this->assertSame('between("attr", 1, 2)', Query::between('attr', 1.0, 2.0));
    }

    public function testBetweenWithStrings(): void {
        $this->assertSame('between("attr", "a", "z")', Query::between('attr', 'a', 'z'));
    }

    public function testSelect(): void {
        $this->assertSame('select(["attr1","attr2"])', Query::select(['attr1', 'attr2']));
    }

    public function testOrderAsc(): void {
        $this->assertSame('orderAsc("attr")', Query::orderAsc('attr'));
    }

    public function testOrderDesc(): void {
        $this->assertSame('orderDesc("attr")', Query::orderDesc('attr'));
    }

    public function testOrderRandom(): void {
        $this->assertSame('{"method":"orderRandom"}', Query::orderRandom());
    }

    public function testCursorBefore(): void {
        $this->assertSame('cursorBefore("attr")', Query::cursorBefore('attr'));
    }

    public function testCursorAfter(): void {
        $this->assertSame('cursorAfter("attr")', Query::cursorAfter('attr'));
    }

    public function testLimit(): void {
        $this->assertSame('limit(1)', Query::limit(1));
    }

    public function testOffset(): void {
        $this->assertSame('offset(1)', Query::offset(1));
    }

    public function testNotContains(): void {
        $this->assertSame('notContains("attr", ["value"])', Query::notContains('attr', 'value'));
    }

    public function testNotSearch(): void {
        $this->assertSame('notSearch("attr", ["keyword1 keyword2"])', Query::notSearch('attr', 'keyword1 keyword2'));
    }

    public function testNotBetweenWithIntegers(): void {
        $this->assertSame('notBetween("attr", 1, 2)', Query::notBetween('attr', 1, 2));
    }

    public function testNotBetweenWithDoubles(): void {
        $this->assertSame('notBetween("attr", 1, 2)', Query::notBetween('attr', 1.0, 2.0));
    }

    public function testNotBetweenWithStrings(): void {
        $this->assertSame('notBetween("attr", "a", "z")', Query::notBetween('attr', 'a', 'z'));
    }

    public function testNotStartsWith(): void {
        $this->assertSame('notStartsWith("attr", ["prefix"])', Query::notStartsWith('attr', 'prefix'));
    }

    public function testNotEndsWith(): void {
        $this->assertSame('notEndsWith("attr", ["suffix"])', Query::notEndsWith('attr', 'suffix'));
    }

    public function testCreatedBefore(): void {
        $this->assertSame('createdBefore("2023-01-01")', Query::createdBefore('2023-01-01'));
    }

    public function testCreatedAfter(): void {
        $this->assertSame('createdAfter("2023-01-01")', Query::createdAfter('2023-01-01'));
    }

    public function testCreatedBetween(): void {
        $this->assertSame('{"method":"createdBetween","values":["2023-01-01","2023-12-31"]}', Query::createdBetween('2023-01-01', '2023-12-31'));
    }

    public function testUpdatedBefore(): void {
        $this->assertSame('updatedBefore("2023-01-01")', Query::updatedBefore('2023-01-01'));
    }

    public function testUpdatedAfter(): void {
        $this->assertSame('updatedAfter("2023-01-01")', Query::updatedAfter('2023-01-01'));
    }

    public function testUpdatedBetween(): void {
        $this->assertSame('{"method":"updatedBetween","values":["2023-01-01","2023-12-31"]}', Query::updatedBetween('2023-01-01', '2023-12-31'));
    }
}
