<?php

declare(strict_types=1);

namespace App\Module\TimeTracking\Infrastructure\Controller;

use App\Module\Core\Domain\Repository\UserRepositoryInterface;
use App\Module\ProjectManagement\Domain\Repository\ProjectRepositoryInterface;
use App\Module\TimeTracking\Domain\Repository\TimeEntryRepositoryInterface;
use App\Module\TimeTracking\Infrastructure\Export\TimeEntryExportService;
use App\Shared\Domain\Contract\ProjectInterface;
use App\Shared\Domain\Contract\UserInterface;
use DateTimeImmutable;
use Exception;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

class TimeEntryExportController extends AbstractController
{
    public function __construct(
        private readonly TimeEntryRepositoryInterface $timeEntryRepository,
        private readonly TimeEntryExportService $exportService,
        private readonly ProjectRepositoryInterface $projectRepository,
        private readonly UserRepositoryInterface $userRepository,
        private readonly Security $security,
    ) {}

    #[Route('/api/time_entries/export', name: 'time_entry_export', methods: ['GET'], priority: 1)]
    #[IsGranted('ROLE_USER')]
    public function __invoke(Request $request): BinaryFileResponse
    {
        $afterStr  = $request->query->getString('after');
        $beforeStr = $request->query->getString('before');

        if ('' === $afterStr || '' === $beforeStr) {
            throw new BadRequestHttpException('Les paramètres "after" et "before" sont obligatoires.');
        }

        try {
            $after  = new DateTimeImmutable($afterStr);
            $before = new DateTimeImmutable($beforeStr);
        } catch (Exception) {
            throw new BadRequestHttpException('Format de date invalide. Utilisez YYYY-MM-DD.');
        }

        if ($after->modify('+12 months') < $before) {
            throw new BadRequestHttpException('La plage de dates ne peut pas dépasser 12 mois.');
        }

        // --- Users ---
        $users = null;
        if (!$this->security->isGranted('ROLE_ADMIN')) {
            /** @var UserInterface $currentUser */
            $currentUser = $this->security->getUser();
            $users       = [$currentUser];
        } else {
            /** @var int[] $userIds */
            $userIds = array_filter(
                array_map('intval', (array) $request->query->all('users')),
                fn (int $id) => $id > 0,
            );
            if ([] !== $userIds) {
                $users = $this->userRepository->findByIds($userIds);
            }
        }

        // --- Client (filter projects by client) ---
        $clientId       = $request->query->getInt('client');
        $clientProjects = null;
        if ($clientId > 0) {
            $clientProjects = $this->projectRepository->findBy(['client' => $clientId]);
        }

        // --- Projects ---
        $projects = null;

        /** @var int[] $projectIds */
        $projectIds = array_filter(
            array_map('intval', (array) $request->query->all('projects')),
            fn (int $id) => $id > 0,
        );
        if ([] !== $projectIds) {
            $projects = $this->projectRepository->findBy(['id' => $projectIds]);
        }

        // Merge: if both client and projects are set, intersect; if only client, use client projects
        if (null !== $clientProjects && null !== $projects) {
            $clientProjectIds = array_map(fn (ProjectInterface $p) => $p->getId(), $clientProjects);
            $projects         = array_values(array_filter($projects, fn (ProjectInterface $p) => in_array($p->getId(), $clientProjectIds, true)));
            if ([] === $projects) {
                $projects = null;
                // No matching projects — force empty result by using a dummy condition
                $entries  = [];
                $tempFile = $this->exportService->generate($entries, $after, $before);
                $filename = sprintf('export-temps-%s_%s.xlsx', $after->format('Y-m-d'), $before->format('Y-m-d'));
                $response = new BinaryFileResponse($tempFile);
                $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename);
                $response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
                $response->deleteFileAfterSend(true);

                return $response;
            }
        } elseif (null !== $clientProjects) {
            $projects = $clientProjects;
        }

        /** @var int[] $tagIds */
        $tagIds = array_filter(
            array_map('intval', (array) $request->query->all('tags')),
            fn (int $id) => $id > 0,
        );

        $entries = $this->timeEntryRepository->findForExport(
            $after,
            $before,
            $users ?: null,
            $projects ?: null,
            $tagIds ?: null,
        );

        $tempFile = $this->exportService->generate($entries, $after, $before);

        $filename = sprintf('export-temps-%s_%s.xlsx', $after->format('Y-m-d'), $before->format('Y-m-d'));

        $response = new BinaryFileResponse($tempFile);
        $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename);
        $response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        $response->deleteFileAfterSend(true);

        return $response;
    }
}
