<?php

declare(strict_types=1);

namespace App\Administration\Application\Command\UpdateBranding;

use App\Administration\Domain\Exception\ContrasteInsuffisantException;
use App\Administration\Domain\Model\SchoolBranding\BrandColor;
use App\Administration\Domain\Model\SchoolBranding\ContrastValidator;
use App\Administration\Domain\Model\SchoolBranding\SchoolBranding;
use App\Administration\Domain\Model\SchoolClass\SchoolId;
use App\Administration\Domain\Repository\SchoolBrandingRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler(bus: 'command.bus')]
final readonly class UpdateBrandingHandler
{
    private const string WHITE = '#FFFFFF';

    public function __construct(
        private SchoolBrandingRepository $brandingRepository,
        private ContrastValidator $contrastValidator,
        private Clock $clock,
    ) {
    }

    public function __invoke(UpdateBrandingCommand $command): SchoolBranding
    {
        $tenantId = TenantId::fromString($command->tenantId);
        $schoolId = SchoolId::fromString($command->schoolId);
        $now = $this->clock->now();

        $branding = $this->brandingRepository->findBySchoolId($schoolId, $tenantId);

        if ($branding === null) {
            $branding = SchoolBranding::creer(
                schoolId: $schoolId,
                tenantId: $tenantId,
                createdAt: $now,
            );
        }

        $primaryColor = $command->primaryColor !== null
            ? new BrandColor($command->primaryColor)
            : null;

        if ($primaryColor !== null) {
            $result = $this->contrastValidator->validate($primaryColor, new BrandColor(self::WHITE));

            if (!$result->passesAA) {
                throw ContrasteInsuffisantException::pourRatio($result->ratio, 4.5);
            }
        }

        $secondaryColor = $command->secondaryColor !== null
            ? new BrandColor($command->secondaryColor)
            : null;
        $accentColor = $command->accentColor !== null
            ? new BrandColor($command->accentColor)
            : null;

        $branding->modifierCouleurs(
            primaryColor: $primaryColor,
            secondaryColor: $secondaryColor,
            accentColor: $accentColor,
            at: $now,
        );

        $this->brandingRepository->save($branding);

        return $branding;
    }
}
