<?php

namespace App\Torrentio\Framework\Controller;

use App\Base\ConfigResolver;
use App\Base\Service\Broadcaster;
use App\Torrentio\Action\Handler\GetMovieOptionsHandler;
use App\Torrentio\Action\Handler\GetTvShowOptionsHandler;
use App\Torrentio\Action\Input\GetMovieOptionsInput;
use App\Torrentio\Action\Input\GetTvShowOptionsInput;
use App\Torrentio\Client\Torrentio;
use App\Torrentio\Exception\TorrentioRateLimitException;
use Carbon\Carbon;
use OneToMany\RichBundle\Contract\ResultInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\Cache;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
use Symfony\UX\Turbo\TurboBundle;

final class WebController extends AbstractController
{
    const REAL_DEBRID_STREAM_URL = 'https://real-debrid.com/streaming-%s';

    public function __construct(
        private readonly GetMovieOptionsHandler $getMovieOptionsHandler,
        private readonly GetTvShowOptionsHandler $getTvShowOptionsHandler,
        private readonly ConfigResolver $configResolver,
        private readonly Broadcaster $broadcaster,
    ) {}

    #[Cache(expires: 3600, public: false, mustRevalidate: true)]
    #[Route('/torrentio/movies/{tmdbId}/{imdbId}', name: 'app_torrentio_movies')]
    public function movieOptions(GetMovieOptionsInput $input, CacheInterface $cache, Request $request): Response
    {
        $cacheId = sprintf(
            "page.torrentio.movies.%s.%s",
            $input->tmdbId,
            $input->imdbId
        );

        if (true === $this->configResolver->isTorrentioCacheEnabled()) {
            $results =  $cache->get($cacheId, function (ItemInterface $item) use ($input, $request) {
                $item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0));
                return $this->getMovieOptionsHandler->handle($input->toCommand());
            });
        } else {
            $results = $this->getMovieOptionsHandler->handle($input->toCommand());
        }

        if ($request->headers->get('Turbo-Frame')) {
            return $this->sendFragmentResponse($results, $request);
        }

        return $this->render('torrentio/movies.html.twig', [
            'results' => $results,
        ]);
    }

    #[Route('/torrentio/tvshows/{tmdbId}/{imdbId}/{season?}/{episode?}', name: 'app_torrentio_tvshows')]
    public function tvShowOptions(GetTvShowOptionsInput $input, CacheInterface $cache, Request $request): Response
    {
        $cacheId = sprintf(
            "page.torrentio.tvshows.%s.%s.%s.%s",
            $input->tmdbId,
            $input->imdbId,
            $input->season,
            $input->episode,
        );

        try {
            if (true === $this->configResolver->isTorrentioCacheEnabled()) {
                $results = $cache->get($cacheId, function (ItemInterface $item) use ($input) {
                    $item->expiresAt(Carbon::now()->addHour()->setMinute(0)->setSecond(0));
                    return $this->getTvShowOptionsHandler->handle($input->toCommand());
                });
            } else {
                $results = $this->getTvShowOptionsHandler->handle($input->toCommand());
            }

            if ($request->headers->get('Turbo-Frame')) {
                return $this->sendFragmentResponse($results, $request);
            }

            return $this->render('torrentio/tvshows.html.twig', [
                'results' => $results,
            ]);
        } catch (TorrentioRateLimitException $exception) {
            $this->broadcaster->alert('Warning', 'Torrentio has rate limited your requests. Please wait a few minutes before trying again.', 'warning');
            return $this->render('bare.html.twig',
                [],
                new Response('Too many requests',
                    Response::HTTP_TOO_MANY_REQUESTS,
                    ['Retry-After' => 4000]
                )
            );
        }
    }

    private function sendFragmentResponse(ResultInterface $result, Request $request): Response
    {
        $request->setRequestFormat(TurboBundle::STREAM_FORMAT);
        return $this->renderBlock(
            'torrentio/fragments.html.twig',
            $request->query->get('block'),
            [
                'results' => $result,
                'target' => $request->query->get('target')
            ]
        );
    }

    #[Route('/torrentio/stream/{url}', name: 'app.torrentio.stream')]
    public function streamVideo(string $url, Torrentio $torrentio): Response
    {
        $destinationUrl = $torrentio->getDestinationUrl(\base64_decode($url));
        $urlPathParts = explode('/', parse_url($destinationUrl)['path']);
        $videoId = $urlPathParts[2];
        $url = sprintf(self::REAL_DEBRID_STREAM_URL, $videoId);
        return $this->redirect($url);
    }
}
