<?php

namespace App\Http\Controllers;

use App\Option;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;

class TMDB extends Controller
{
    CONST API_BASE = 'https://api.themoviedb.org/3/';
    CONST APPEND_TO_RESPONSE = 'videos,images,recommendations,similar,credits,movie_credits,tv_credits,keywords';
    CONST INCLUDE_IMAGE_LANGUAGE = 'en, null';

    private $page;
    private $language;
    private $api_key;

    public function __construct(int $page = 1)
    {
        $this->api_key = get_tmdb_key();
        $this->page = $page;
        $this->language = app()->getLocale();
    }

    public function getMovie(int $id)
    {
        $action = "movie/{$id}";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getTv(int $id)
    {
        $action = "tv/{$id}";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getTvSeason(int $id, int $season)
    {
        $action = "tv/{$id}/season/{$season}";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getTvSeasonEpisode(int $id, int $season, int $episode)
    {
        $action = "tv/{$id}/season/{$season}/episode/{$episode}";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getMovieTv(string $action)
    {
        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getGenreLists()
    {
        $action = "genre/movie/list";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getGenreMovies(int $id)
    {
        $action = "genre/{$id}/movies";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getPeoplePopular()
    {
        $action = "person/popular";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getPeople(int $id)
    {
        $action = "person/{$id}";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getPeopleMovies(int $id)
    {
        $action = "person/{$id}/movie_credits";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    public function getImdbMovie(string $imdb_id)
    {
        $action = "find/{$imdb_id}";
        $option = ['external_source'=>'imdb_id'];
        $results = $this->_call($action, $option);

        if(empty($results->movie_results)) {
            abort(404);
        }

        return $results->movie_results[0];
    }

    public function getImdbTv(string $imdb_id)
    {
        $action = "find/{$imdb_id}";
        $option = ['external_source'=>'imdb_id'];
        $results = $this->_call($action, $option);

        if(empty($results->tv_episode_results) && empty($results->tv_results)) {
            abort(404);
        }

        return $results;
    }

    public function getSearch(string $query)
    {
        return $this->_call('search/multi', ['query' => $query]);
    }

    public function getKeywordMovie($id)
    {
        $action = "keyword/{$id}/movies";

        if (is_cache() === 'true') {
            $key = $action.$this->page.$this->language;
            $results = Cache::remember($key, get_cache_expired(), function () use ($action) {
                return $this->_call($action);
            });
        }else{
            $results = $this->_call($action);
        }

        return $results;
    }

    private function _call(string $action, array $option = [])
    {
        $query = [
            'api_key' => $this->api_key,
            'language' => $this->language,
            'page' => $this->page,
            'append_to_response' => self::APPEND_TO_RESPONSE,
            'include_image_language' => self::INCLUDE_IMAGE_LANGUAGE,
        ];
        $query = !empty($option) ? array_merge($query, $option) : $query;
        $query = Arr::query($query);

        $url = self::API_BASE.$action.'?'.$query;

        $response = Http::get($url);

        if (!$response) {
            return false;
        }

        $body = $response->getBody();
        $results = json_decode($body);

        if (isset($results->status_code)) {
            abort(403, $results->status_message);
        }

        return json_decode($body);
    }
}
