<?php

namespace App\Download\Framework\Controller;

use App\Base\Service\Broadcaster;
use App\Download\Action\Handler\DeleteDownloadHandler;
use App\Download\Action\Handler\DownloadMediaHandler;
use App\Download\Action\Handler\PauseDownloadHandler;
use App\Download\Action\Handler\ResumeDownloadHandler;
use App\Download\Action\Input\DeleteDownloadInput;
use App\Download\Action\Input\DownloadMediaInput;
use App\Download\Action\Input\DownloadSeasonInput;
use App\Download\Action\Input\PauseDownloadInput;
use App\Download\Action\Input\ResumeDownloadInput;
use App\Download\DownloadEvents;
use App\Download\Framework\Entity\Download;
use App\Download\Framework\Repository\DownloadRepository;
use App\EventLog\Action\Command\AddEventLogCommand;
use App\Search\Action\Command\GetMediaInfoCommand;
use App\Search\Action\Handler\GetMediaInfoHandler;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;

class ApiController extends AbstractController
{
    public function __construct(
        private DownloadRepository   $downloadRepository,
        private MessageBusInterface  $bus,
        private readonly Broadcaster $broadcaster, private readonly RequestStack $requestStack,
    ) {}

    #[Route('/api/download/{mediaType?}/{imdbId?}/{season?}/{episode?}', name: 'api_download', methods: ['GET', 'POST'])]
    public function download(
        DownloadMediaInput $input,
        DownloadMediaHandler $handler,
        GetMediaInfoHandler $getMediaInfoHandler,
    ): Response {
        $media = $getMediaInfoHandler->handle(new GetMediaInfoCommand($input->imdbId, $input->mediaType));
        $download = $this->downloadRepository->insertNew(
            $this->getUser(),
            $input->imdbId,
            $input->mediaType,
            $media->media->title,
            $input->season,
            $input->episode,
        );
        $input->setDownloadId($download->getId());
        $input->setUserId($this->getUser()->getId());
        $input->setMercureAlertTopic($this->requestStack->getSession()->get('mercure_alert_topic'));
        $input->toCommand();

        $this->bus->dispatch(new AddEventLogCommand(
            $this->getUser(),
            DownloadEvents::DOWNLOAD_ADDED->type(),
            DownloadEvents::DOWNLOAD_ADDED->message(),
            (array) $download
        ));

        try {
            $this->bus->dispatch($input->toCommand());
        } catch (\Throwable $exception) {
            return $this->json(['error' => $exception->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        $this->broadcaster->alert(
            title: 'Success',
            message: "Added to Queue."
        );

        return $this->json(['status' => 200, 'message' => 'Added to Queue']);
    }

    #[Route('/api/download/{downloadId}', name: 'api_download_delete', methods: ['DELETE'])]
    public function deleteDownload(
        DeleteDownloadInput $input,
        DeleteDownloadHandler $handler,
    ): Response {
        $result = $handler->handle($input->toCommand());
        $this->broadcaster->alert(
            title: 'Success',
            message: "{$result->download->getTitle()} has been deleted.",
        );

        return $this->json($result);
    }

    #[Route('/api/download/{downloadId}/pause', name: 'api_download_pause', methods: ['PATCH'])]
    public function pauseDownload(
        PauseDownloadInput $input,
        PauseDownloadHandler $handler,
    ): Response {
        $result = $handler->handle($input->toCommand());
        $this->broadcaster->alert(
            title: 'Success',
            message: "{$result->download->getTitle()} has been Paused.",
        );

        return $this->json(['status' => 200, 'message' => 'Download Paused']);
    }

    #[Route('/api/download/{downloadId}/resume', name: 'api_download_resume', methods: ['PATCH'])]
    public function resumeDownload(
        ResumeDownloadInput $input,
        ResumeDownloadHandler $handler,
    ): Response {
        $result = $handler->handle($input->toCommand());
        $this->broadcaster->alert(
            title: 'Success',
            message: "{$result->download->getTitle()} has been Resumed.",
        );

        return $this->json(['status' => 200, 'message' => 'Download Resumed']);
    }

    #[Route('/api/download/season/{imdbId}/{season}', name: 'api_download_season', methods: ['GET'])]
    public function downloadSeason(
        DownloadSeasonInput $input,
    ): Response {
        $input->userId = $this->getUser()->getId();
        $this->bus->dispatch($input->toCommand());
        $this->broadcaster->alert(
            title: 'Success',
            message: "Your download for season $input->season has been added to the queue.",
        );

        return $this->json(['status' => 200, 'message' => 'Download Resumed']);
    }

    #[Route('/api/download', name: 'api_get_downloads', methods: ['GET'])]
    public function getDownloads(DownloadRepository $repository): Response
    {
        $downloads = $repository->findBy(['user' => $this->getUser()]);

        return $this->json(['status' => 200, 'message' => 'Success', 'data' => ['downloads' => $downloads]]);
    }

    #[Route('/api/download/{id}', name: 'api_get_download', methods: ['GET'])]
    public function getDownload(Download $download): Response
    {
        if ($download->getUser() === $this->getUser()) {
            return $this->json(['status' => 200, 'message' => 'Success', 'data' => ['download' => $download]]);
        }

        return $this->json(['status' => 404, 'message' => 'Success'], 404);
    }
}
