<?php

declare(strict_types=1);

namespace Apexl\Io\Tests\FeatureTests\Entities;

use Apexl\Io\TestInfrastructure\FeatureTest;
use Apexl\Io\Tests\Infrastructure\ReadOnlyFieldTestEntity;
use PHPUnit\Framework\Attributes\Test;

/**
 * READ_ONLY_FIELDS is enforced when a row is updated, and only then: an insert is the one
 * moment those fields are legitimately written.
 *
 * The distinction matters because "is this an insert?" cannot be answered from the entity —
 * an entity with a natural key carries its key before the row exists — so the operator makes
 * the call, at the point it already knows whether it found a row.
 */
class ReadOnlyFieldsTest extends FeatureTest
{
    private string $table;

    #[Test]
    public function aReadOnlyFieldIsWrittenOnInsert(): void
    {
        $entity = new ReadOnlyFieldTestEntity();
        $entity->name = 'first';
        $entity->note = 'a';
        $entity->store();

        $this->assertSame('first', $this->storedName($entity->id));
    }

    #[Test]
    public function aReadOnlyFieldCannotBeChangedOnUpdate(): void
    {
        $entity = new ReadOnlyFieldTestEntity();
        $entity->name = 'first';
        $entity->note = 'a';
        $entity->store();

        $entity->name = 'changed';
        $entity->note = 'b';
        $entity->store();

        $this->assertSame('first', $this->storedName($entity->id), 'the read-only field moved');
        $this->assertSame('b', $this->storedNote($entity->id), 'the writable field did not move');
    }

    private function storedName(int $id): string
    {
        return (string) self::$db->select($this->table)->fields(['name'])
            ->where('id', $id)->execute()->fetch()->name;
    }

    private function storedNote(int $id): string
    {
        return (string) self::$db->select($this->table)->fields(['note'])
            ->where('id', $id)->execute()->fetch()->note;
    }

    protected function setUp(): void
    {
        parent::setUp();

        $this->table = 'read_only_fields__' . str_replace('.', '', uniqid('', true));
        ReadOnlyFieldTestEntity::$tableName = $this->table;

        self::$db->executeSql(
            <<<SQL
            create table `$this->table`
            (
                id int(11) unsigned auto_increment primary key,
                name varchar(255) not null,
                note varchar(255) not null
            )
            SQL
        );
    }

    protected function tearDown(): void
    {
        parent::tearDown();

        self::$db->executeSql("drop table `$this->table`");
        ReadOnlyFieldTestEntity::$tableName = null;
    }
}
