from __future__ import annotations

import asyncio
import io
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Literal
from .common import ArtemisError

import aiohttp

if TYPE_CHECKING:
    from ..bot import Artemis


@dataclass
class DeepLResult:
    src: str
    dst: str
    translation: str


class API:
    def __init__(self, bot: Artemis, token: str):
        self.base_url = "http://127.0.0.1:3000"
        self.token = token
        self.session: aiohttp.ClientSession = bot.session
        self.HEADERS = {"User-Agent": bot.real_user_agent}
        self.AUTHED_HEADERS = {**self.HEADERS, "Authorization": f"Bearer {self.token}"}

    async def _aioread(self, fp):
        return await asyncio.to_thread(fp.read)

    async def _request(
        self,
        method: str,
        path: str,
        authed: bool = False,
        res_type: Literal["json", "text", "bytes"] = "json",
        **kwargs,
    ) -> Any:
        headers = self.AUTHED_HEADERS if authed else self.HEADERS
        async with self.session.request(
            method, self.base_url + path, headers=headers, **kwargs
        ) as r:
            match res_type:
                case "json":
                    return await r.json()
                case "text":
                    return await r.text()
                case "bytes":
                    return await r.read()

    async def screenshot(
        self,
        url: str,
        selector: str | None = None,
        waitForSelector: str | None = None,
        waitForFunction: str | None = None,
    ) -> io.BytesIO:
        """Returns a PNG screenshot of the website at url with optional selector."""
        params = {"url": url}
        if selector:
            params["selector"] = selector
        if waitForSelector:
            params["waitForSelector"] = waitForSelector
        if waitForFunction:
            params["waitForFunction"] = waitForFunction

        res: bytes = await self._request(
            "GET", "/webdriver/screenshot", authed=True, res_type="bytes", params=params
        )
        return io.BytesIO(res)

    async def deepl(self, text: str, src: str = "auto", dst: str = "en") -> DeepLResult:
        """Returns DeepL translated text."""
        data = {"src": src.lower(), "dst": dst.lower(), "text": text}

        async with self.session.post(
            self.base_url + "/webdriver/deepl", json=data, headers=self.AUTHED_HEADERS
        ) as r:
            data = await r.json()
            if not r.ok:
                raise ArtemisError(f"DeepL Error: `{data.get('error', 'Unknown')}`")
            return DeepLResult(**data)
