<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Api\Controller;

use App\Administration\Infrastructure\Security\SecurityUser;
use App\Scolarite\Application\Command\DuplicateHomework\DuplicateHomeworkCommand;
use App\Scolarite\Application\Command\DuplicateHomework\DuplicateHomeworkHandler;
use App\Scolarite\Domain\Exception\DuplicationValidationException;
use App\Scolarite\Domain\Exception\HomeworkNotFoundException;
use App\Scolarite\Domain\Exception\NonProprietaireDuDevoirException;
use App\Scolarite\Domain\Model\Homework\Homework;
use App\Scolarite\Domain\ValueObject\ClassValidationResult;
use App\Shared\Infrastructure\Tenant\TenantContext;

use function array_map;
use function is_array;
use function is_string;

use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;

final readonly class DuplicateHomeworkController
{
    public function __construct(
        private DuplicateHomeworkHandler $handler,
        private TenantContext $tenantContext,
        private Security $security,
        private MessageBusInterface $eventBus,
    ) {
    }

    #[Route('/api/homework/{id}/duplicate', name: 'api_homework_duplicate', methods: ['POST'])]
    public function __invoke(string $id, Request $request): JsonResponse
    {
        if (!$this->tenantContext->hasTenant()) {
            throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
        }

        $user = $this->security->getUser();

        if (!$user instanceof SecurityUser) {
            throw new UnauthorizedHttpException('Bearer', 'Authentification requise.');
        }

        $body = $request->toArray();

        $targetClassIds = $body['targetClassIds'] ?? null;

        if (!is_array($targetClassIds) || $targetClassIds === []) {
            throw new BadRequestHttpException('Au moins une classe cible est requise.');
        }

        /** @var array<string, string> $dueDates */
        $dueDates = [];
        $rawDueDates = $body['dueDates'] ?? [];

        if (is_array($rawDueDates)) {
            foreach ($rawDueDates as $classId => $date) {
                if (is_string($classId) && is_string($date)) {
                    $dueDates[$classId] = $date;
                }
            }
        }

        $classIds = [];

        foreach ($targetClassIds as $item) {
            if (!is_string($item)) {
                throw new BadRequestHttpException('Les identifiants de classe doivent être des chaînes.');
            }

            $classIds[] = $item;
        }

        try {
            $command = new DuplicateHomeworkCommand(
                tenantId: (string) $this->tenantContext->getCurrentTenantId(),
                homeworkId: $id,
                teacherId: $user->userId(),
                targetClassIds: $classIds,
                dueDates: $dueDates,
            );

            $result = ($this->handler)($command);

            foreach ($result->homeworks as $homework) {
                foreach ($homework->pullDomainEvents() as $event) {
                    $this->eventBus->dispatch($event);
                }
            }

            $response = [
                'data' => array_map(static fn (Homework $h): array => [
                    'id' => (string) $h->id,
                    'classId' => (string) $h->classId,
                    'title' => $h->title,
                    'dueDate' => $h->dueDate->format('Y-m-d'),
                    'status' => $h->status->value,
                ], $result->homeworks),
            ];

            if ($result->warnings !== []) {
                $response['warnings'] = array_map(static fn (ClassValidationResult $r): array => [
                    'classId' => (string) $r->classId,
                    'warning' => $r->warning,
                ], $result->warnings);
            }

            return new JsonResponse($response, Response::HTTP_CREATED);
        } catch (HomeworkNotFoundException $e) {
            throw new NotFoundHttpException($e->getMessage());
        } catch (NonProprietaireDuDevoirException $e) {
            throw new NotFoundHttpException($e->getMessage());
        } catch (DuplicationValidationException $e) {
            return new JsonResponse([
                'error' => $e->getMessage(),
                'results' => array_map(static fn (ClassValidationResult $r): array => [
                    'classId' => (string) $r->classId,
                    'valid' => $r->valid,
                    'error' => $r->error,
                ], $e->results),
            ], Response::HTTP_BAD_REQUEST);
        } catch (InvalidUuidStringException $e) {
            throw new BadRequestHttpException('UUID invalide : ' . $e->getMessage());
        }
    }
}
