import base64
import json
import logging
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo

log = logging.getLogger(__name__)


class LoyaAuth:
    def __init__(self, email: str, password: str, apikey: str, **kwargs):
        self.email = email
        self.password = password
        self.apikey = apikey
        self.sess_id = ""

    def apply_auth(self, sess_id: str | None = ""):
        if not sess_id or sess_id == "" or sess_id == "None":
            raise Exception("sess_id is empty")

        self.sess_id = sess_id

    def decode_play_session_cookie(self) -> dict:
        """
        Декодирует куку PLAY2AUTH_SESS_ID от Play Framework
        """
        try:
            # Play иногда добавляет --- в начало/конец — убираем
            cleaned = self.sess_id.strip().split("---")[0]

            # Декодируем Base64 (с паддингом, если нужно)
            missing_padding = len(cleaned) % 4
            if missing_padding:
                cleaned += "=" * (4 - missing_padding)

            decoded_bytes = base64.b64decode(cleaned)
            decoded_str = decoded_bytes.decode("utf-8")

            # Парсим как JSON
            data = json.loads(decoded_str)
            return data

        except Exception as e:
            print("Не удалось декодировать куку:", e)
            print("Сырая Base64 строка:", self.sess_id[:100] + "...")
            return {"error": str(e), "raw": self.sess_id}

    def convert_date(self, date_str: str) -> datetime:
        if "[" in date_str:
            date_str = date_str.split("[", 1)[0]
        date_str = date_str.replace("Z", "+00:00")

        # Парсим строку с таймзоной
        exp_dt = datetime.fromisoformat(date_str)
        if exp_dt.tzinfo is None:
            exp_dt = exp_dt.replace(tzinfo=ZoneInfo("Europe/Moscow"))

        return exp_dt

    def is_session_expired(self) -> bool:
        if not self.sess_id:
            return True

        try:
            # Парсим куку
            payload = self.decode_play_session_cookie()

            # Проверяем время истечения сессии
            last_used_dt = self.convert_date(payload["lastUsedDateTime"])
            exp_dt = last_used_dt + timedelta(seconds=payload["cookieMaxAge"] - 1)
            now = datetime.now(ZoneInfo("Europe/Moscow"))

            return now >= exp_dt
        except (ValueError, KeyError, TypeError, OSError) as e:
            log.warning(f"Не удалось проверить срок действия сессии: {e}")
            return True  # если не удалось распарсить — считаем просроченной

    def session_expires_in_minutes(self) -> int:
        if not self.sess_id:
            return 0
        try:
            payload = self.decode_play_session_cookie()
            last_used_dt = self.convert_date(payload["lastUsedDateTime"])
            exp_dt = last_used_dt + timedelta(seconds=payload["cookieMaxAge"] - 1)

            delta = exp_dt - datetime.now().astimezone()
            return int(delta.total_seconds() // 60)
        except (ValueError, KeyError, TypeError, OSError) as e:
            log.warning(f"Не удалось проверить срок действия сессии: {e}")
            return 0
