"""Tests for authentication manager."""

import base64
import json
import time

import pytest

from dvgateway.auth.manager import AuthManager, _parse_jwt_payload
from dvgateway.observability.logger import create_logger
from dvgateway.types import ApiKeyAuth, JwtAuth


def _make_jwt(exp: float, sub: str = "test") -> str:
    """Create a fake JWT token (header.payload.signature)."""
    header = base64.urlsafe_b64encode(json.dumps({"alg": "HS256"}).encode()).decode().rstrip("=")
    payload = base64.urlsafe_b64encode(
        json.dumps({"exp": exp, "iat": time.time(), "sub": sub}).encode()
    ).decode().rstrip("=")
    sig = base64.urlsafe_b64encode(b"fake_signature").decode().rstrip("=")
    return f"{header}.{payload}.{sig}"


class TestParseJwtPayload:
    def test_valid_jwt(self) -> None:
        token = _make_jwt(exp=9999999999)
        payload = _parse_jwt_payload(token)
        assert payload["sub"] == "test"
        assert payload["exp"] == 9999999999

    def test_invalid_format(self) -> None:
        with pytest.raises(ValueError, match="Invalid JWT format"):
            _parse_jwt_payload("not.a.valid.jwt.with.extra")

    def test_legacy_two_part_token(self) -> None:
        """Legacy 2-part gateway tokens (tenantID|timestamp.signature) are supported."""
        ts = int(time.time())
        payload = f"|{ts}"
        payload_b64 = base64.urlsafe_b64encode(payload.encode()).decode().rstrip("=")
        token = f"{payload_b64}.fakesig"
        result = _parse_jwt_payload(token)
        assert result["exp"] == ts + 86400
        assert result["tid"] == ""

    def test_legacy_two_part_with_tenant(self) -> None:
        ts = int(time.time())
        payload = f"tenant123|{ts}"
        payload_b64 = base64.urlsafe_b64encode(payload.encode()).decode().rstrip("=")
        token = f"{payload_b64}.fakesig"
        result = _parse_jwt_payload(token)
        assert result["tid"] == "tenant123"

    def test_one_part_invalid(self) -> None:
        with pytest.raises(ValueError, match="Invalid JWT format"):
            _parse_jwt_payload("noseparator")


class TestAuthManager:
    def test_jwt_auth_preloads_token(self) -> None:
        token = _make_jwt(exp=9999999999)
        logger = create_logger(level="error")
        auth = AuthManager(JwtAuth(token=token), "http://localhost", logger)
        assert auth._cached_token == token

    def test_build_http_url_no_params(self) -> None:
        logger = create_logger(level="error")
        auth = AuthManager(ApiKeyAuth(api_key="test"), "http://localhost:8080", logger)
        url = auth.build_http_url("/api/v1/sessions")
        assert url == "http://localhost:8080/api/v1/sessions"

    def test_build_http_url_with_params(self) -> None:
        logger = create_logger(level="error")
        auth = AuthManager(ApiKeyAuth(api_key="test"), "http://localhost:8080/", logger)
        url = auth.build_http_url("/api/v1/sessions", {"tenantId": "abc"})
        assert "tenantId=abc" in url

    @pytest.mark.asyncio
    async def test_build_ws_url(self) -> None:
        token = _make_jwt(exp=9999999999)
        logger = create_logger(level="error")
        auth = AuthManager(JwtAuth(token=token), "http://localhost:8080", logger)
        url = await auth.build_ws_url("/api/v1/ws/stream", {"linkedid": "123"})
        assert url.startswith("ws://")
        assert "linkedid=123" in url
        assert "token=" in url

    @pytest.mark.asyncio
    async def test_build_ws_url_https(self) -> None:
        token = _make_jwt(exp=9999999999)
        logger = create_logger(level="error")
        auth = AuthManager(JwtAuth(token=token), "https://gateway.example.com", logger)
        url = await auth.build_ws_url("/api/v1/ws/callinfo")
        assert url.startswith("wss://")
