<?php
declare(strict_types=1);

namespace Apexl\Vault\Tests;

use Apexl\Vault\Interfaces\QueryBuilderInterface;
use Apexl\Vault\Interfaces\SchemaInterface;
use Apexl\Vault\Operators\Drivers\MongoDb;
use Apexl\Vault\Operators\Drivers\MySql;
use Apexl\Vault\Schemas\MongoSchema;
use Apexl\Vault\Schemas\MysqlSchema;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use ReflectionMethod;
use stdClass;

/**
 * describe(), createTable() and keyIsAutoIncrementing() used to sit on the query
 * builder, which is how mongodb ended up implementing
 * `createTable(..., string $engine = 'INNODB')` — an argument that means nothing to a
 * store with no tables and no engines. They are a contract of their own now, and the
 * MySQL-shaped details are the MySQL implementation's business.
 */
final class SchemaSeparationTest extends TestCase
{
    #[Test]
    public function ddlIsOffTheBuilder(): void
    {
        foreach (['describe', 'createTable', 'keyIsAutoIncrementing'] as $method) {
            $this->assertFalse(
                method_exists(QueryBuilderInterface::class, $method),
                sprintf('%s() is back on the builder', $method),
            );
        }
    }

    #[Test]
    public function aDriverHandsBackASchemaForItsOwnStore(): void
    {
        $cfg = new stdClass();
        $cfg->driver = 'mysql';

        $this->assertInstanceOf(MysqlSchema::class, (new MySql($cfg))->schema());
    }

    /**
     * mongodb's constructor needs a live client, so assert the wiring by declaration
     * rather than by construction — the driver still has to promise a schema.
     */
    #[Test]
    public function everyDriverPromisesASchema(): void
    {
        foreach ([MySql::class, MongoDb::class] as $driver) {
            $this->assertSame(
                SchemaInterface::class,
                (string) (new ReflectionMethod($driver, 'schema'))->getReturnType(),
                sprintf('%s does not hand back a schema', $driver),
            );
        }
    }

    /** The argument that gave the misfiling away. */
    #[Test]
    public function createTableNoLongerAsksCallersAboutEngines(): void
    {
        $parameters = array_map(
            static fn($p): string => $p->getName(),
            (new ReflectionMethod(SchemaInterface::class, 'createTable'))->getParameters(),
        );

        $this->assertSame(['table', 'colList', 'existsCheck'], $parameters);
    }

    #[Test]
    public function aSchemalessStoreReportsNoColumnsRatherThanRefusing(): void
    {
        $this->assertSame([], (new MongoSchema())->describe('anything'));
    }
}
