<?php

declare(strict_types=1);

namespace App\SuperAdmin\Domain\Model\Establishment;

use App\Shared\Domain\AggregateRoot;
use App\Shared\Domain\Tenant\TenantId;
use App\SuperAdmin\Domain\Event\EtablissementCree;
use App\SuperAdmin\Domain\Event\EtablissementDesactive;
use App\SuperAdmin\Domain\Exception\EstablishmentDejaInactifException;
use App\SuperAdmin\Domain\Model\SuperAdmin\SuperAdminId;
use DateTimeImmutable;

use function sprintf;

/**
 * Aggregate Root for an Establishment (tenant) — lives in master database.
 *
 * Each Establishment maps to a tenant with its own database.
 */
final class Establishment extends AggregateRoot
{
    public private(set) ?DateTimeImmutable $lastActivityAt = null;

    private function __construct(
        public private(set) EstablishmentId $id,
        public private(set) TenantId $tenantId,
        public private(set) string $name,
        public private(set) string $subdomain,
        public private(set) string $databaseName,
        public private(set) EstablishmentStatus $status,
        public private(set) DateTimeImmutable $createdAt,
        public private(set) ?SuperAdminId $createdBy,
    ) {
    }

    public static function creer(
        string $name,
        string $subdomain,
        SuperAdminId $createdBy,
        DateTimeImmutable $createdAt,
    ): self {
        $tenantId = TenantId::generate();

        $establishment = new self(
            id: EstablishmentId::generate(),
            tenantId: $tenantId,
            name: $name,
            subdomain: $subdomain,
            databaseName: sprintf('classeo_tenant_%s', str_replace('-', '', (string) $tenantId)),
            status: EstablishmentStatus::ACTIF,
            createdAt: $createdAt,
            createdBy: $createdBy,
        );

        $establishment->recordEvent(new EtablissementCree(
            establishmentId: $establishment->id,
            tenantId: $establishment->tenantId,
            name: $name,
            subdomain: $subdomain,
            occurredOn: $createdAt,
        ));

        return $establishment;
    }

    public function desactiver(DateTimeImmutable $at): void
    {
        if ($this->status !== EstablishmentStatus::ACTIF) {
            throw EstablishmentDejaInactifException::pour($this->id);
        }

        $this->status = EstablishmentStatus::INACTIF;

        $this->recordEvent(new EtablissementDesactive(
            establishmentId: $this->id,
            occurredOn: $at,
        ));
    }

    public function enregistrerActivite(DateTimeImmutable $at): void
    {
        $this->lastActivityAt = $at;
    }

    /**
     * @internal For Infrastructure use only
     */
    public static function reconstitute(
        EstablishmentId $id,
        TenantId $tenantId,
        string $name,
        string $subdomain,
        string $databaseName,
        EstablishmentStatus $status,
        DateTimeImmutable $createdAt,
        ?SuperAdminId $createdBy = null,
        ?DateTimeImmutable $lastActivityAt = null,
    ): self {
        $establishment = new self(
            id: $id,
            tenantId: $tenantId,
            name: $name,
            subdomain: $subdomain,
            databaseName: $databaseName,
            status: $status,
            createdAt: $createdAt,
            createdBy: $createdBy,
        );

        $establishment->lastActivityAt = $lastActivityAt;

        return $establishment;
    }
}
