"""End-to-end tests: full OpenAPI -> LAPIS conversion."""

from __future__ import annotations

from pathlib import Path

from lapis_spec.converter import convert, convert_to_string
from lapis_spec.parser.openapi_loader import load_openapi

FIXTURES = Path(__file__).parent / "fixtures"


class TestInvoiceApiConversion:
    def test_loads_and_converts_invoice_api(self):
        doc = load_openapi(FIXTURES / "invoice_api.yaml", skip_validation=True)
        lapis_doc = convert(doc)

        assert lapis_doc.meta.api == "Invoice Service"
        assert lapis_doc.meta.base == "https://api.example.com/v2"
        assert lapis_doc.meta.version == "2.2.0"
        assert lapis_doc.meta.auth == "bearer header:Authorization"

    def test_types_extracted(self):
        doc = load_openapi(FIXTURES / "invoice_api.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        type_names = [t.name for t in lapis_doc.types]
        assert "ApiError" in type_names
        assert "Address" in type_names
        assert "InvoiceLine" in type_names
        assert "Invoice" in type_names
        assert "Customer" in type_names

    def test_operations_extracted(self):
        doc = load_openapi(FIXTURES / "invoice_api.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        op_names = [op.name for op in lapis_doc.ops]
        assert "create_invoice" in op_names
        assert "list_invoices" in op_names
        assert "get_invoice" in op_names
        assert "delete_invoice" in op_names
        assert "create_customer" in op_names
        assert "get_customer" in op_names

    def test_webhooks_extracted(self):
        doc = load_openapi(FIXTURES / "invoice_api.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        assert len(lapis_doc.webhooks) >= 1
        wh_names = [wh.name for wh in lapis_doc.webhooks]
        assert "invoice_paid" in wh_names

    def test_errors_extracted(self):
        doc = load_openapi(FIXTURES / "invoice_api.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        assert len(lapis_doc.errors) > 0
        codes = {e.code for e in lapis_doc.errors}
        assert 400 in codes or 401 in codes

    def test_emitted_text_has_all_sections(self):
        doc = load_openapi(FIXTURES / "invoice_api.yaml", skip_validation=True)
        text = convert_to_string(doc)
        assert "# LAPIS v0.1.0" in text
        assert "[meta]" in text
        assert "[types]" in text
        assert "[ops]" in text
        assert "[webhooks]" in text
        assert "[errors]" in text

    def test_list_invoices_paginated(self):
        doc = load_openapi(FIXTURES / "invoice_api.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        list_op = next(op for op in lapis_doc.ops if op.name == "list_invoices")
        assert "+paginated" in list_op.modifiers

    def test_invoice_metadata_since(self):
        doc = load_openapi(FIXTURES / "invoice_api.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        from lapis_spec.models.lapis import LapisObjectType
        invoice_type = next(
            t for t in lapis_doc.types
            if isinstance(t, LapisObjectType) and t.name == "Invoice"
        )
        meta_field = next(f for f in invoice_type.fields if f.name == "metadata")
        assert meta_field.since == "2.1"


class TestMinimalApiConversion:
    def test_minimal_conversion(self):
        doc = load_openapi(FIXTURES / "minimal_api.yaml", skip_validation=True)
        text = convert_to_string(doc)
        assert "[meta]" in text
        assert "api: Minimal API" in text
        assert "base: https://api.minimal.com" in text
        assert "[ops]" in text
        assert "health_check GET /health" in text

    def test_minimal_no_optional_sections(self):
        doc = load_openapi(FIXTURES / "minimal_api.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        assert lapis_doc.webhooks == []
        assert lapis_doc.limits is None
        assert lapis_doc.flows == []


class TestPetstoreConversion:
    def test_petstore_conversion(self):
        doc = load_openapi(FIXTURES / "petstore.yaml", skip_validation=True)
        lapis_doc = convert(doc)

        assert lapis_doc.meta.api == "Petstore"
        assert lapis_doc.meta.base == "https://petstore.example.com/v1"

        op_names = [op.name for op in lapis_doc.ops]
        assert "list_pets" in op_names
        assert "create_pet" in op_names
        assert "get_pet" in op_names
        assert "delete_pet" in op_names

    def test_petstore_types(self):
        doc = load_openapi(FIXTURES / "petstore.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        type_names = [t.name for t in lapis_doc.types]
        assert "Pet" in type_names
        assert "Error" in type_names

    def test_petstore_errors(self):
        doc = load_openapi(FIXTURES / "petstore.yaml", skip_validation=True)
        lapis_doc = convert(doc)
        assert len(lapis_doc.errors) > 0

    def test_petstore_text_output(self):
        doc = load_openapi(FIXTURES / "petstore.yaml", skip_validation=True)
        text = convert_to_string(doc)
        assert "# LAPIS v0.1.0" in text
        assert "[meta]" in text
        assert "api: Petstore" in text
        assert "[types]" in text
        assert "[ops]" in text
        assert "[errors]" in text


class TestRoundTrip:
    def test_yaml_json_produce_same_output(self, tmp_path: Path):
        yaml_path = FIXTURES / "minimal_api.yaml"
        doc_yaml = load_openapi(yaml_path, skip_validation=True)

        import json
        json_path = tmp_path / "minimal_api.json"
        json_path.write_text(json.dumps(doc_yaml, indent=2), encoding="utf-8")
        doc_json = load_openapi(json_path, skip_validation=True)

        text_yaml = convert_to_string(doc_yaml)
        text_json = convert_to_string(doc_json)
        assert text_yaml == text_json
