"""E2E tests for Availity client — auth, eligibility, claims, async polling."""

from __future__ import annotations

from typing import Any

import httpx
import pytest

from claim_validator.clearinghouse.exceptions import ClearinghouseTimeoutError
from claim_validator.clearinghouse.factory import get_clearinghouse_client
from claim_validator.clearinghouse.providers.availity import AvailityClient


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


def _make(handler: Any) -> AvailityClient:
    transport = httpx.MockTransport(handler)
    c = AvailityClient(client_id="e2e", client_secret="e2e")
    c._client.close()
    c._client = httpx.Client(transport=transport, base_url="https://api.availity.com")
    return c


class TestAvailityFullFlow:
    """E2E: OAuth2 -> eligibility -> claims -> async polling -> status."""

    def test_eligibility_happy_path(self) -> None:
        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                return _token_ok()
            return httpx.Response(200, json={
                "requestId": "AV-E2E-001",
                "coverages": [{"status": "active", "planName": "BCBS Gold"}],
            })

        c = _make(handler)
        result = c.check_eligibility({"payer_id": "BCBS01"})
        assert result.status == "ok"
        assert result.plan_info["coverages"][0]["planName"] == "BCBS Gold"
        c.close()

    def test_claim_submission_sync_response(self) -> None:
        """Synchronous payer returns immediately without polling."""
        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                return _token_ok()
            return httpx.Response(200, json={"status": "accepted", "id": "AV-SYNC-001"})

        c = _make(handler)
        result = c.submit_claim({"npi": "1234567893"})
        assert result.accepted is True
        assert result.reference_id == "AV-SYNC-001"
        c.close()

    def test_claim_submission_async_polling_success(self) -> None:
        """Async payer: submit -> poll -> complete."""
        poll_count = {"n": 0}

        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                return _token_ok()
            if "claims" in str(req.url).lower() and req.method == "POST":
                return httpx.Response(200, json={
                    "status": "pending",
                    "statusUrl": "/availity/v1/claims/status/ASYNC-1",
                    "id": "ASYNC-1",
                })
            if "status" in str(req.url).lower():
                poll_count["n"] += 1
                if poll_count["n"] >= 2:
                    return httpx.Response(200, json={"status": "complete", "id": "ASYNC-1"})
                return httpx.Response(200, json={"status": "pending", "id": "ASYNC-1"})
            return httpx.Response(200, json={})

        c = _make(handler)
        c._poll_interval = 0.01
        result = c.submit_claim({"npi": "1234567893"})
        assert result.accepted is True
        assert poll_count["n"] >= 2
        c.close()

    def test_async_polling_timeout(self) -> None:
        """Async payer that never completes raises timeout."""
        def handler(req: httpx.Request) -> httpx.Response:
            if "/token" in str(req.url):
                return _token_ok()
            if req.method == "POST":
                return httpx.Response(200, json={
                    "status": "pending",
                    "statusUrl": "/availity/v1/claims/status/TIMEOUT-1",
                    "id": "TIMEOUT-1",
                })
            return httpx.Response(200, json={"status": "pending", "id": "TIMEOUT-1"})

        c = _make(handler)
        c._poll_interval = 0.01
        c._max_poll_attempts = 2
        with pytest.raises(ClearinghouseTimeoutError, match="polling"):
            c.submit_claim({"npi": "1234567893"})
        c.close()

    def test_factory_registration(self) -> None:
        c = get_clearinghouse_client("availity", client_id="x", client_secret="y")
        assert isinstance(c, AvailityClient)
        c.close()
