<?php

namespace App\Torrentio\Client;

use Aimeos\Map;
use App\Download\Framework\Repository\DownloadRepository;
use App\Torrentio\Result\ResultFactory;
use App\Torrentio\Exception\TorrentioRateLimitException;
use Psr\Log\LoggerInterface;

class Torrentio
{
    private array $badDownloadUrls = [];

    public function __construct(
        private readonly HttpClient         $client,
        private readonly DownloadRepository $downloadRepository, private readonly LoggerInterface $logger,
    ) {
        $badDownloadUrls = $this->downloadRepository->badDownloadUrls();
        $this->badDownloadUrls = Map::from($badDownloadUrls)
            ->map(fn ($url) => $url['url'])
            ->toArray();
    }

    public function search(string $imdbCode, string $type, bool $parseResults = true): array
    {
        $cacheTags = ['torrentio', $type, $imdbCode];
        $results = $this->client->get($imdbCode, $cacheTags);

        if (true === $parseResults) {
            return $this->parse($results, $imdbCode);
        }

        return $results;
    }

    public function fetchEpisodeResults(string $imdbId, int $season, int $episode, bool $parseResults = true): array
    {
        $cacheTags = ['torrentio', 'tvshows', 'torrentio.tvshows', $imdbId, "torrentio.$imdbId", "$imdbId.$season", "torrentio.$imdbId.$season", "$imdbId.$season.$episode", "torrentio.$imdbId.$season.$episode"];
        $results = $this->client->get("$imdbId:$season:$episode", $cacheTags);

        if (null === $results) {
            throw new TorrentioRateLimitException();
        }

        if (true === $parseResults) {
            return $this->parse($results, $imdbId);
        }

        return $results;
    }

    public function parse(array $data, string $imdbId): array
    {
        $results = [];
        foreach ($data['streams'] as $stream) {
            if (!str_starts_with($stream['url'], "https")) {
                continue;
            }

            $url = explode('/', $stream['url']);
            $filename = urldecode(end($url));
            $url[count($url) - 1] = $filename;
            $url = implode('/', $url);

            if (in_array($stream['url'], $this->badDownloadUrls)) {
                $this->logger->warning($stream['url'] . ' was skipped because it was identified as a bad download url.');
                continue;
            }

            if (
                array_key_exists('behaviorHints', $stream) &&
                array_key_exists('bingeGroup', $stream['behaviorHints'])
            ) {
                $bingeGroup = $stream['behaviorHints']['bingeGroup'];
            } else {
                $bingeGroup = '-';
            }

            $result = ResultFactory::map(
                $stream['url'],
                $stream['title'],
                $bingeGroup,
                $imdbId
            );

            $results[] = $result;
        }

        return $results;
    }

    public function getDestinationUrl(string $url)
    {
        $request = get_headers($url)[8];
        return explode(' ', $request)[1];
    }
}
