from typing import Dict, List, Generator
from datetime import datetime
from urllib import parse
import pandas as pd
import requests
import logging
import csv
import os


class TheMovieDatabase:
    __api_keys = {
        "v3": """3c7a65f36185e501b84bfc4e959ad6c5""",
        "v4": """eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIzYzdhNjVmMzYxODVlNTAxYjg0YmZjNGU5NTlhZDZjNSIsInN1YiI6IjVhY2UyMWI3MGUwYTI2MzFlNzA0NjJmYyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.fJqxalTRbyTbvkvAWHHoy239upo1n5v2jLL4kCoScvk""",
    }

    __base_url = "http://api.themoviedb.org"
    __discover_urls = {
        "movie": "3/discover/movie"
    }

    # TODO: add restart capability
    __current_page_index = 0
    __max_pages = 1000

    __data_path = "./Data/tmdb.csv"
    __data_file = None

    __csv_writer = None
    __csv_reader = None
    __fieldnames = ["vote_count", "id", "video", "vote_average",
                    "title", "popularity", "poster_path", "original_language",
                    "original_title", "backdrop_path", "adult", "overview", "release_date"]

    __processed_count = 0
    __supported_discoveries = ["movie"]

    def __enter__(self):
        if os.path.isfile(self.__data_path):
            logging.info("Data already present.")
            self.__data_file = open(self.__data_path, "r+")
            self.__csv_writer = csv.DictWriter(self.__data_file, self.__fieldnames, dialect="unix")
            self.__csv_reader = csv.DictReader(self.__data_file, dialect="unix")
        else:
            logging.info("No data present. Writing headers to csv.")
            self.__data_file = open(self.__data_path, "w")
            self.__csv_writer = csv.DictWriter(self.__data_file, self.__fieldnames, dialect="unix")
            self.__csv_writer.writeheader()

        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.__data_file.close()

    def discover(self, discovery_type: str, date_gte: str, date_lte: str) -> int:
        """Requests movies from the TMDB API sorted by popularity in descending order. Clean results store in csv format.

        Args:
            discovery_type: The type of discovery to request from TMDB. Not all types are supported.
            date_gte: The upper bound of the release date in years.
            date_lte: The lower bound of the release date in years.

        Returns: The number of processed movies.
        """
        if datetime.strptime(date_gte, "%Y") > datetime.strptime(date_lte, "%Y"):
            raise ValueError("Date lower bound higher than date upper bound: [lower_bound, upper_bound]=",
                             [date_gte, date_lte])

        if discovery_type not in self.__supported_discoveries:
            raise ValueError("Discovery type not supported: ", discovery_type)

        payload = {
            "api_key": self.__api_keys["v3"],
            "primary_release_date.lte": date_lte,
            "primary_release_date.gte": date_gte,
            "include_video": False,
            "include_adult": False,
            "sort_by": "popularity.desc",
            "language": "en-US",
        }

        for i in range(self.__current_page_index, self.__max_pages):
            payload["page"] = i + 1

            response = requests.get(parse.urljoin(self.__base_url, self.__discover_urls["movie"]), params=payload)
            if response.status_code != 200:
                raise Exception("API Request failed: ", response.json())

            results = self.__clean(response.json()["results"])
            self.__to_csv(results)
            self.__processed_count += len(results)

            logging.info("Page {} -- Processed {}\n".format(payload["page"], self.__processed_count))

        logging.info("Processed in this run: {}".format(self.__processed_count))

        return self.__processed_count

    def __to_csv(self, results: list) -> None:
        """Write the movie resource to csv.

        Args:
            results: Write the movie representation to a csv file.
        """
        for movie in results:
            self.__csv_writer.writerow(movie)

    @staticmethod
    def __clean(results: List) -> List:
        """Remove useless fields from result set.

        Args:
            results: The results returned by the API call as a list.

        Returns:
            List: Results without some useless fields.

        """
        return list(map(TheMovieDatabase.__remove_genres, results))

    @staticmethod
    def __remove_genres(movie: Dict) -> Dict:
        """Remove the genre ids from the movie resource.

        Args:
            movie: The movie resource returned by TMDB.

        Returns:
            Dict: The movie resource without the `genre_ids` field.


        """
        del movie["genre_ids"]
        return movie

    def movies(self) -> Generator[Dict, None, None]:
        for row in self.__csv_reader:
            yield row


if __name__ == "__main__":
    with TheMovieDatabase() as tmdb:
        # tmdb.discover("movie", "2000", "2018")

        ########################
        #CREATE RDF
        count = 0;
        not_found = 0;
        from Processes.Create_RDF import create_rdf
        for movie in tmdb.movies():
            g = create_rdf(movie['title'],movie['release_date'],movie['vote_average'],movie['popularity'],movie['vote_count'],movie['id'],movie['title']);
            if(g == 0):
                not_found += 1;
                logging.info(movie['title'])
            else:
                if (count == 0):
                    prev_graph = g;

                else:
                    prev_graph += g;
                prev_graph.serialize(destination='output.txt', format='turtle')
            count += 1;
            logging.info(count)
        pass
    #prev_graph.serialize(destination='output.txt',format='turtle')
    logging.info(not_found)
