<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Persistence\Doctrine;

use App\Scolarite\Domain\Model\Competency\CustomCompetencyLevel;
use App\Scolarite\Domain\Model\Competency\CustomCompetencyLevelId;
use App\Scolarite\Domain\Repository\CustomCompetencyLevelRepository;
use App\Shared\Domain\Tenant\TenantId;

use function array_map;

use Doctrine\DBAL\Connection;
use Override;

final readonly class DoctrineCustomCompetencyLevelRepository implements CustomCompetencyLevelRepository
{
    public function __construct(
        private Connection $connection,
    ) {
    }

    #[Override]
    public function save(CustomCompetencyLevel $level): void
    {
        $this->connection->executeStatement(
            'INSERT INTO competency_levels (id, tenant_id, code, name, color, sort_order)
             VALUES (:id, :tenant_id, :code, :name, :color, :sort_order)
             ON CONFLICT (tenant_id, code) DO UPDATE SET
                 name = EXCLUDED.name,
                 color = EXCLUDED.color,
                 sort_order = EXCLUDED.sort_order',
            [
                'id' => (string) $level->id,
                'tenant_id' => (string) $level->tenantId,
                'code' => $level->code,
                'name' => $level->name,
                'color' => $level->color,
                'sort_order' => $level->sortOrder,
            ],
        );
    }

    #[Override]
    public function findByTenant(TenantId $tenantId): array
    {
        $rows = $this->connection->fetchAllAssociative(
            'SELECT * FROM competency_levels WHERE tenant_id = :tenant_id ORDER BY sort_order ASC',
            ['tenant_id' => (string) $tenantId],
        );

        return array_map($this->hydrate(...), $rows);
    }

    #[Override]
    public function hasByTenant(TenantId $tenantId): bool
    {
        /** @var string|int $count */
        $count = $this->connection->fetchOne(
            'SELECT COUNT(*) FROM competency_levels WHERE tenant_id = :tenant_id',
            ['tenant_id' => (string) $tenantId],
        );

        return (int) $count > 0;
    }

    /** @param array<string, mixed> $row */
    private function hydrate(array $row): CustomCompetencyLevel
    {
        /** @var string $id */
        $id = $row['id'];
        /** @var string $tenantId */
        $tenantId = $row['tenant_id'];
        /** @var string $code */
        $code = $row['code'];
        /** @var string $name */
        $name = $row['name'];
        /** @var string|null $color */
        $color = $row['color'];
        /** @var string|int $sortOrder */
        $sortOrder = $row['sort_order'];

        return CustomCompetencyLevel::reconstitute(
            id: CustomCompetencyLevelId::fromString($id),
            tenantId: TenantId::fromString($tenantId),
            code: $code,
            name: $name,
            color: $color,
            sortOrder: (int) $sortOrder,
        );
    }
}
