<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Service;

use App\Administration\Application\Service\HomeworkRulesValidationResult;
use App\Administration\Application\Service\HomeworkRulesValidator;
use App\Administration\Application\Service\RuleViolation;
use App\Administration\Application\Service\ValidDueDateSuggester;
use App\Administration\Domain\Model\HomeworkRules\HomeworkRule;
use App\Administration\Domain\Model\HomeworkRules\HomeworkRules;
use App\Administration\Domain\Repository\HomeworkRulesRepository;
use App\Scolarite\Application\Port\CurrentCalendarProvider;
use App\Scolarite\Application\Port\HomeworkRulesChecker;
use App\Scolarite\Application\Port\HomeworkRulesCheckResult;
use App\Scolarite\Application\Port\RuleWarning;
use App\Shared\Domain\Tenant\TenantId;

use function array_map;

use DateTimeImmutable;
use Override;

/**
 * Adaptateur qui délègue la vérification des règles au bounded context Administration.
 */
final readonly class AdministrationHomeworkRulesChecker implements HomeworkRulesChecker
{
    public function __construct(
        private HomeworkRulesRepository $rulesRepository,
        private HomeworkRulesValidator $validator,
        private ValidDueDateSuggester $suggester,
        private CurrentCalendarProvider $calendarProvider,
    ) {
    }

    #[Override]
    public function verifier(
        TenantId $tenantId,
        DateTimeImmutable $dueDate,
        DateTimeImmutable $creationDate,
    ): HomeworkRulesCheckResult {
        $rules = $this->rulesRepository->findByTenantId($tenantId);

        if ($rules === null) {
            return HomeworkRulesCheckResult::ok();
        }

        $result = $this->validator->valider($rules, $dueDate, $creationDate);

        return $this->toCheckResult($result, $rules, $dueDate, $creationDate);
    }

    private function toCheckResult(
        HomeworkRulesValidationResult $result,
        HomeworkRules $rules,
        DateTimeImmutable $dueDate,
        DateTimeImmutable $creationDate,
    ): HomeworkRulesCheckResult {
        $suggestedDates = [];

        if ($result->estBloquant()) {
            $calendar = $this->calendarProvider->forCurrentYear($rules->tenantId);
            $suggestedDates = array_map(
                static fn (DateTimeImmutable $d): string => $d->format('Y-m-d'),
                $this->suggester->suggerer($dueDate, $rules, $creationDate, calendar: $calendar),
            );
        }

        return new HomeworkRulesCheckResult(
            warnings: array_map(
                fn (RuleViolation $v): RuleWarning => new RuleWarning(
                    ruleType: $v->ruleType->value,
                    message: $v->message,
                    params: $this->findRuleParams($rules, $v),
                ),
                $result->violations,
            ),
            bloquant: $result->estBloquant(),
            suggestedDates: $suggestedDates,
        );
    }

    /**
     * @return array<string, mixed>
     */
    private function findRuleParams(HomeworkRules $rules, RuleViolation $violation): array
    {
        foreach ($rules->rules as $rule) {
            /** @var HomeworkRule $rule */
            if ($rule->type === $violation->ruleType) {
                return $rule->params;
            }
        }

        return [];
    }
}
