import pytest
import httpx
from unittest.mock import patch, MagicMock
from vericorp import VeriCorp, Company, ValidationResult, CountriesResponse, HealthResponse, BatchResponse
from vericorp.errors import InvalidTaxIdError, NotFoundError, RateLimitError


COMPANY_JSON = {
    "tax_id": "PT502011378",
    "country": "PT",
    "name": "UNIVERSIDADE DO MINHO",
    "address": {"street": "LG DO PACO", "city": "BRAGA", "postal_code": "4700-320", "country": "PT"},
    "source": "nifpt",
    "data_quality": "full",
    "cached": True,
    "fetched_at": "2026-01-01T00:00:00Z",
}

VALIDATION_JSON = {
    "tax_id": "PT502011378",
    "country": "PT",
    "format_valid": True,
    "vat_valid": True,
    "company_name": "UNIVERSIDADE DO MINHO",
}

COUNTRIES_JSON = {
    "total": 29,
    "enriched": 8,
    "vat_validation": 28,
    "countries": [{"code": "PT", "name": "Portugal", "enriched": True, "source": "nifpt", "vat_validation": True}],
}

HEALTH_JSON = {
    "status": "healthy",
    "timestamp": "2026-01-01T00:00:00Z",
}

BATCH_JSON = {
    "total": 1,
    "successful": 1,
    "results": [COMPANY_JSON],
}


def mock_response(status_code: int = 200, json_data: dict | None = None, headers: dict | None = None) -> httpx.Response:
    response = MagicMock(spec=httpx.Response)
    response.status_code = status_code
    response.is_success = 200 <= status_code < 300
    response.json.return_value = json_data or {}
    response.headers = headers or {}
    return response


class TestVeriCorp:
    def test_lookup(self):
        client = VeriCorp("test-key")
        with patch.object(client._client, "request", return_value=mock_response(200, COMPANY_JSON)):
            result = client.lookup("PT502011378")
            assert isinstance(result, Company)
            assert result.name == "UNIVERSIDADE DO MINHO"
            assert result.country == "PT"

    def test_lookup_gb(self):
        client = VeriCorp("test-key")
        gb_json = {**COMPANY_JSON, "tax_id": "GB00445790", "country": "GB", "source": "companies_house"}
        with patch.object(client._client, "request", return_value=mock_response(200, gb_json)):
            result = client.lookup_gb("00445790")
            assert result.source == "companies_house"

    def test_validate(self):
        client = VeriCorp("test-key")
        with patch.object(client._client, "request", return_value=mock_response(200, VALIDATION_JSON)):
            result = client.validate("PT502011378")
            assert isinstance(result, ValidationResult)
            assert result.format_valid is True
            assert result.vat_valid is True

    def test_batch(self):
        client = VeriCorp("test-key")
        with patch.object(client._client, "request", return_value=mock_response(200, BATCH_JSON)):
            result = client.batch(["PT502011378"])
            assert isinstance(result, BatchResponse)
            assert result.total == 1

    def test_countries(self):
        client = VeriCorp("test-key")
        with patch.object(client._client, "request", return_value=mock_response(200, COUNTRIES_JSON)):
            result = client.countries()
            assert isinstance(result, CountriesResponse)
            assert result.total == 29

    def test_health(self):
        client = VeriCorp("test-key")
        with patch.object(client._client, "request", return_value=mock_response(200, HEALTH_JSON)):
            result = client.health()
            assert isinstance(result, HealthResponse)
            assert result.status == "healthy"

    def test_invalid_tax_id(self):
        client = VeriCorp("test-key")
        with patch.object(client._client, "request", return_value=mock_response(400)):
            with pytest.raises(InvalidTaxIdError):
                client.lookup("INVALID")

    def test_not_found(self):
        client = VeriCorp("test-key")
        with patch.object(client._client, "request", return_value=mock_response(404)):
            with pytest.raises(NotFoundError):
                client.lookup("PT000000000")

    def test_rate_limit(self):
        client = VeriCorp("test-key", max_retries=0)
        with patch.object(client._client, "request", return_value=mock_response(429, headers={"Retry-After": "30"})):
            with pytest.raises(RateLimitError) as exc_info:
                client.lookup("PT502011378")
            assert exc_info.value.retry_after == 30

    def test_context_manager(self):
        with VeriCorp("test-key") as client:
            assert client._client is not None

    def test_custom_timeout(self):
        client = VeriCorp("test-key", timeout=5.0)
        assert client._timeout == 5.0
