<?php

declare(strict_types=1);

namespace Apexl\Io\User\Tests\FeatureTests;

use Apexl\Io\TestInfrastructure\FeatureTest;
use Apexl\Io\User\Entities\UserEntity;
use Apexl\Io\User\Interfaces\StampedActorResolverInterface;
use PHPUnit\Framework\Attributes\Test;

/**
 * `created_by` is stamped by AddCreatedByToEntitiesOnSave on HOOK__BEFORE_FIRST_STORE.
 *
 * A FeatureTest, not a UnitTest: the hook is registered by userModule, and this
 * asserts on the row that actually lands in the database — the defect it covers
 * lived in Entity::callHooks(), which handed the second hook the ORIGINAL input
 * instead of the first hook's result, so this hook's work was discarded for
 * every insert between 20 Jan 2026 and apexl/io 3.10.7.
 */
final class CreatedByIsStampedOnFirstStoreTest extends FeatureTest
{
    private function newUser(): UserEntity
    {
        $user = new UserEntity();
        $user->first_name = 'Created';
        $user->last_name = 'By';
        $user->email = 'created-by-' . bin2hex(random_bytes(6)) . '@example.com';
        $user->password = 'irrelevant';
        $user->salt = 'irrelevant';

        return $user;
    }

    /** getField(), not the magic accessor — `created_by` casts to a userEntity. */
    private function storedCreatedBy(UserEntity $user): mixed
    {
        return UserEntity::find((int) $user->id)->getField('created_by');
    }

    /**
     * Asserted against the bound resolver rather than against the current user's id.
     * The default resolver answers with that id, but an application whose audit columns
     * reference its own people table binds its own — and this test is about the stamp
     * reaching the row, not about which id the application considers the actor.
     */
    #[Test]
    public function firstStoreStampsTheResolvedActor(): void
    {
        $actorId = \Apexl\Io\container()->get(StampedActorResolverInterface::class)->id();

        $user = $this->newUser();
        $user->store();

        $stored = $this->storedCreatedBy($user);

        $this->assertSame($actorId, $stored === null ? null : (int) $stored);
    }

    #[Test]
    public function anExplicitlyAssignedCreatedBySurvivesTheHook(): void
    {
        // First-write-wins: provenance set by the caller is not the framework's
        // to overwrite. Regression cover for the guard restored in io-user 3.10.0.
        $user = $this->newUser();
        $user->created_by = 4242;
        $user->store();

        $this->assertSame(4242, (int) $this->storedCreatedBy($user));
    }
}
