"""E2E tests for Change Healthcare client — auth through to all API operations."""

from __future__ import annotations

import time
from typing import Any

import httpx
import pytest

from claim_validator.clearinghouse.exceptions import (
    ClearinghouseAuthError,
    ClearinghouseError,
)
from claim_validator.clearinghouse.factory import get_clearinghouse_client
from claim_validator.clearinghouse.providers.change_healthcare import (
    ChangeHealthcareClient,
)


def _token_ok(token: str = "e2e-token") -> httpx.Response:
    return httpx.Response(200, json={"access_token": token, "expires_in": 3600})


def _make(handler: Any) -> ChangeHealthcareClient:
    transport = httpx.MockTransport(handler)
    c = ChangeHealthcareClient(client_id="e2e-id", client_secret="e2e-secret")
    c._client.close()
    c._client = httpx.Client(transport=transport, base_url="https://apigw.changehealthcare.com")
    return c


class TestChangeHealthcareFullFlow:
    """E2E: OAuth2 auth -> eligibility -> claims -> status."""

    def test_auth_then_eligibility(self) -> None:
        """Single flow: authenticate then check eligibility."""
        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                return _token_ok()
            return httpx.Response(200, json={
                "controlNumber": "CTL001",
                "benefitsInformation": [{"code": "1", "name": "Active Coverage"}],
            })

        c = _make(handler)
        result = c.check_eligibility({"payer_id": "60054", "subscriber_id": "MEM001"})
        assert result.status == "ok"
        assert result.reference_id == "CTL001"
        c.close()

    def test_auth_then_submit_claim(self) -> None:
        """Single flow: authenticate then submit claim."""
        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                return _token_ok()
            return httpx.Response(200, json={
                "status": "accepted",
                "claimReference": "CHC-E2E-001",
            })

        c = _make(handler)
        result = c.submit_claim({"npi": "1234567893", "claim_type": "837P"})
        assert result.accepted is True
        assert result.reference_id == "CHC-E2E-001"
        c.close()

    def test_auth_then_claim_status(self) -> None:
        """Single flow: authenticate then check claim status."""
        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                return _token_ok()
            return httpx.Response(200, json={
                "status": "completed",
                "claimStatus": "paid",
                "claimReference": "CHC-E2E-001",
            })

        c = _make(handler)
        result = c.check_claim_status("CHC-E2E-001")
        assert result.claim_status == "paid"
        c.close()

    def test_token_reused_across_operations(self) -> None:
        """Token should be fetched once and reused across multiple calls."""
        token_calls = {"n": 0}

        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                token_calls["n"] += 1
                return _token_ok()
            return httpx.Response(200, json={"status": "ok"})

        c = _make(handler)
        c.check_eligibility({"payer_id": "test"})
        c.submit_claim({"npi": "1234567893"})
        c.check_claim_status("REF-1")
        assert token_calls["n"] == 1  # Only one token request
        c.close()

    def test_rate_limited_status_check(self) -> None:
        """429 from claim status should raise ClearinghouseError."""
        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                return _token_ok()
            return httpx.Response(429, headers={"Retry-After": "60"}, json={})

        c = _make(handler)
        with pytest.raises(ClearinghouseError, match="rate limited"):
            c.check_claim_status("REF-1")
        c.close()

    def test_factory_registration(self) -> None:
        """'change' provider creates ChangeHealthcareClient via factory."""
        c = get_clearinghouse_client("change", client_id="x", client_secret="y")
        assert isinstance(c, ChangeHealthcareClient)
        assert c.provider_name == "change"
        c.close()
