import httpx
import logging
from typing import Optional, Any


class JournalApi:
    BASE_URL = "https://msapi.top-academy.ru/api/v2"
    APP_KEY = "6a56a5df2667e65aab73ce76d1dd737f7d1faef9c52e8b8c55ac75f565d8e8a6"

    def __init__(self, timeout: float = 15.0):
        self.timeout = timeout
        self.token: Optional[str] = None
        self.client: Optional[httpx.AsyncClient] = None

    async def __aenter__(self):
        self.client = httpx.AsyncClient(
            base_url=self.BASE_URL,
            timeout=self.timeout,
            headers={
                "accept": "application/json, text/plain, */*",
                "content-type": "application/json",
                "origin": "https://journal.top-academy.ru",
                "referer": "https://journal.top-academy.ru/",
                "authorization": "Bearer null",
                "x-cache-client": "600",
                "user-agent": "Mozilla/5.0",
            },
        )
        return self

    async def __aexit__(self, exc_type, exc, tb):
        await self.client.aclose()

    # ===============================================
    # ---------------- Base request -----------------
    # ===============================================
    async def _request(
        self,
        method: str,
        endpoint: str,
        *,
        json: dict = None,
        params: dict = None,
        allowed_statuses=(200,)
    ) -> Any:

        try:
            response = await self.client.request(
                method,
                endpoint,
                json=json,
                params=params,
            )

            if response.status_code not in allowed_statuses:
                response.raise_for_status()

            if response.content:
                return response.json()

            return None

        except httpx.HTTPError as e:
            logging.error(f"{method} {endpoint} failed: {e}")
            raise

    def _update_token(self, token: str):
        self.token = token
        self.client.headers.update({
            "authorization": f"Bearer {token}"
        })

    # ===============================================
    # -------------------- LOGIN --------------------
    # ===============================================

    async def login(self, username: str, password: str):

        payload = {
            "application_key": self.APP_KEY,
            "id_city": None,
            "username": username,
            "password": password
        }

        data = await self._request(
            "POST",
            "/auth/login",
            json=payload
        )

        token = data.get("access_token")
        if not token:
            raise RuntimeError("Login failed: no access_token")

        self._update_token(token)

        return data

    # ===============================================
    # ------------------- METHODS -------------------
    # ===============================================


    # Информация о пользователе
    async def get_user_info(self):
        return await self._request("GET", "/settings/user-info")

    # Будущие экзамены
    async def get_future_exams(self):
        return await self._request("GET", "dashboard/info/future-exams")

    # Посещаемость
    async def get_attendance(self):
        return await self._request("GET", "dashboard/chart/attendance")

    # Расписание на месяц
    async def get_schedule_month(self, date):
        return await self._request("GET", f"schedule/operations/get-month?date_filter={date}")

    # Расписание на день
    async def get_schedule_day(self, date):
        return await self._request("GET", f"schedule/operations/get-by-date?date_filter={date}")

    # Средний балл
    async def get_average_grade(self):
        return await self._request("GET", "dashboard/chart/average-progress")

    # Лидеры группы
    async def get_group_leaders(self):
        return await self._request("GET", "dashboard/progress/leader-group")

    # Счеты домашних заданий
    async def get_homework_counters(self):

        counter_types = [
            {1: 'Просроченные'},
            {2: 'На проверке'},
            {3: 'Текущие'},
            {4: 'Всего'},
            {5: 'Неизвестно'},
        ]

        return await self._request("GET", "count/homework")

