import json
import time
from base64 import b64decode
from typing import Optional
from urllib.parse import quote

from aiohttp import ClientSession
from yt_dlp.utils import random_user_agent

from . import utils


class uNoGSError(Exception):
    pass


class uNoGS:
    token: Optional[str]
    token_expiry: Optional[int]

    _API_BASE = "https://unogs.com/api"
    _EMPTY_PARAMS = [
        "country_andorunique",
        "start_year",
        "end_year",
        "start_rating",
        "end_rating",
        "genrelist",
        "type",
        "audio",
        "subtitle",
        "audiosubtitle_andor",
        "person",
        "filterby",
        "orderby",
    ]
    _COUNTRY_LIST = "21,23,26,29,33,36,307,45,39,327,331,334,265,337,336,269,267,357,378,65,67,390,392,268,400,402,408,412,447,348,270,73,34,425,432,436,46,78"
    _DEFAULT_HEADERS = {
        "User-Agent": random_user_agent(),
        "Referer": "https://unogs.com",
        "Referrer": "http://unogs.com",
    }
    _DETAILS = ["detail", "bgimages", "genres", "people", "countries", "episodes"]

    def __init__(self, session: ClientSession):
        self.session: ClientSession = session
        self.token = None
        self.token_expiry = None

    async def _validate_token(self):
        if not self.token or self.token_expiry < utils.time():
            await self._fetch_token()

    async def _fetch_token(self):
        data = {"user_name": round(time.time(), 3)}
        async with self.session.post(
            self._API_BASE + "/user", headers=self._DEFAULT_HEADERS, data=data
        ) as r:
            data = await r.json()

        token = data["token"]["access_token"]
        self.token = token
        token_data = token.split(".")[1] + "=="
        token_data = b64decode(token_data).decode()
        self.token_expiry = json.loads(token_data)["exp"]

    async def _request(self, path: str, **kwargs):
        await self._validate_token()
        headers = {**self._DEFAULT_HEADERS, "Authorization": f"Bearer {self.token}"}
        cookies = {"authtoken": "token"}

        async with self.session.get(
            self._API_BASE + path, headers=headers, cookies=cookies, **kwargs
        ) as r:
            return await r.json()

    async def search(self, query: str):
        params = {
            "limit": "20",
            "offset": "0",
            "query": quote(query),
            "countrylist": self._COUNTRY_LIST,
        }
        for param in self._EMPTY_PARAMS:
            params[param] = ""
        return await self._request("/search", params=params)

    async def fetch_details(self, nfid, kind="detail"):
        if kind not in self._DETAILS:
            raise uNoGSError("Incorrect detail kind.")
        return await self._request(f"/title/{kind}", params={"netflixid": nfid})
