from __future__ import annotations

import importlib.util
import os
from pathlib import Path

import pytest
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes


MODULE_PATH = Path(__file__).parent.parent / "tme_cookie.py"


def load_module():
    spec = importlib.util.spec_from_file_location("tme_cookie_under_test", MODULE_PATH)
    module = importlib.util.module_from_spec(spec)
    assert spec.loader is not None
    spec.loader.exec_module(module)
    return module


def encrypt_v10(key: bytes, iv: bytes, plain: bytes) -> bytes:
    padder = padding.PKCS7(128).padder()
    padded = padder.update(plain) + padder.finalize()
    encryptor = Cipher(algorithms.AES(key), modes.CBC(iv)).encryptor()
    return b"v10" + iv + encryptor.update(padded) + encryptor.finalize()


def test_decrypts_rms_v10_cookie_with_embedded_iv_and_mac_prefix():
    module = load_module()
    key = bytes.fromhex("628846145161f2c0ab14544e97f0c954")
    iv = b"0123456789abcdef"
    mac_prefix = bytes(range(32))
    encrypted = encrypt_v10(key, iv, mac_prefix + b"session-value")

    assert module._decrypt_cookie_value(encrypted, key) == "session-value"


def test_cache_is_rejected_after_ttl(tmp_path, monkeypatch):
    module = load_module()
    monkeypatch.setattr(module, "_CACHE_DIR", tmp_path)
    module._write_cache("kapi", "a=b", now=100)

    assert module._read_cache("kapi", ttl=60, now=159) == "a=b"
    assert module._read_cache("kapi", ttl=60, now=161) is None
    assert (tmp_path / "kapi.json").stat().st_mode & 0o777 == 0o600


def test_keychain_failure_falls_back_to_cdp(tmp_path, monkeypatch):
    module = load_module()
    monkeypatch.setattr(module, "_CACHE_DIR", tmp_path)
    monkeypatch.delenv("KAPI_TMEOA_COOKIE", raising=False)
    monkeypatch.delenv("KAPI_TMEOA_COOKIE_FILE", raising=False)
    monkeypatch.setattr(
        module,
        "_read_chrome_cookies",
        lambda _domain: (_ for _ in ()).throw(module.CookieError("keychain failed")),
    )
    monkeypatch.setattr(
        module,
        "_read_cookies_via_cdp",
        lambda _domains, recover=False: {"ticket": "ok"},
    )

    result = module.get_cookie(
        "kapi",
        ["tmeoa.com"],
        env_prefix="KAPI_TMEOA",
        cache_name="kapi",
        allow_browser=True,
        allow_cdp=True,
    )

    assert result == {"cookie": "ticket=ok", "source": "cdp"}


def test_invalid_keychain_cookie_falls_back_to_cdp(tmp_path, monkeypatch):
    module = load_module()
    monkeypatch.setattr(module, "_CACHE_DIR", tmp_path)
    monkeypatch.delenv("KAPI_TMEOA_COOKIE", raising=False)
    monkeypatch.delenv("KAPI_TMEOA_COOKIE_FILE", raising=False)
    monkeypatch.setattr(module, "_read_chrome_cookies", lambda _domain: {"old": "bad"})
    recover_calls = []

    def read_cdp(_domains, recover=False):
        recover_calls.append(recover)
        return {"new": "good"} if recover else {"old": "bad"}

    monkeypatch.setattr(module, "_read_cookies_via_cdp", read_cdp)

    result = module.get_cookie(
        "kapi",
        ["tmeoa.com"],
        env_prefix="KAPI_TMEOA",
        cache_name="kapi",
        validator=lambda cookie: cookie == "new=good",
    )

    assert result == {"cookie": "new=good", "source": "cdp"}
    assert recover_calls == [False, True]

