"""Integration tests for Symbol Registry write paths and edge cases.

Covers duplicate detection, alias/source creation, watchlist CRUD,
competitor relationship lifecycle, and exposure profile management.

Uses the ``registry_client`` and ``seed_ids`` fixtures from conftest.py.
"""

import pytest

pytestmark = pytest.mark.asyncio


# ---------------------------------------------------------------------------
# Task 6: Write Paths and Edge Cases
# ---------------------------------------------------------------------------


class TestRegistryDuplicateCompany:
    """POST /companies — duplicate ticker+exchange returns 409."""

    async def test_duplicate_company_returns_409(self, registry_client, seed_ids):
        """POST /companies — duplicate ticker+exchange returns 409."""
        payload = {
            "ticker": "AAPL",
            "legal_name": "Apple Inc Duplicate",
            "exchange": "NASDAQ",
            "sector": "Technology",
            "industry": "Consumer Electronics",
            "market_cap_bucket": "mega",
        }
        resp = await registry_client.post("/companies", json=payload)
        assert resp.status_code == 409


class TestRegistryCompanyNotFound:
    """GET /companies/{id} — 404 for non-existent UUID."""

    async def test_company_not_found(self, registry_client):
        """GET /companies/{id} — 404 for non-existent UUID."""
        fake_id = "00000000-0000-4000-ffff-000000000099"
        resp = await registry_client.get(f"/companies/{fake_id}")
        assert resp.status_code == 404


class TestRegistryAliasCreate:
    """POST /companies/{id}/aliases — create alias returns 201."""

    async def test_create_alias(self, registry_client, seed_ids):
        """POST /companies/{id}/aliases — create alias returns 201."""
        company_id = seed_ids["companies"]["AAPL"]
        payload = {"alias": "Apple Computer", "alias_type": "historical"}
        resp = await registry_client.post(f"/companies/{company_id}/aliases", json=payload)
        assert resp.status_code == 201
        data = resp.json()
        assert "id" in data
        assert data["alias"] == "Apple Computer"
        assert data["alias_type"] == "historical"


class TestRegistrySourceCreate:
    """POST /companies/{id}/sources — create and validate sources."""

    async def test_create_source(self, registry_client, seed_ids):
        """POST /companies/{id}/sources — create source returns 201."""
        company_id = seed_ids["companies"]["AAPL"]
        payload = {
            "source_type": "news_api",
            "source_name": "Test News Source",
            "config": {},
            "credibility_score": 0.7,
        }
        resp = await registry_client.post(f"/companies/{company_id}/sources", json=payload)
        assert resp.status_code == 201
        data = resp.json()
        assert "id" in data
        assert data["source_type"] == "news_api"
        assert data["source_name"] == "Test News Source"

    async def test_create_source_invalid_type(self, registry_client, seed_ids):
        """POST /companies/{id}/sources — invalid source_type returns 422."""
        company_id = seed_ids["companies"]["AAPL"]
        payload = {
            "source_type": "invalid_type",
            "source_name": "Bad Source",
        }
        resp = await registry_client.post(f"/companies/{company_id}/sources", json=payload)
        assert resp.status_code == 422


class TestRegistryWatchlistCRUD:
    """Watchlist creation, member management, and duplicate detection."""

    async def test_create_watchlist(self, registry_client):
        """POST /watchlists — create watchlist returns 201."""
        payload = {"name": "IntTest Watchlist", "description": "Integration test"}
        resp = await registry_client.post("/watchlists", json=payload)
        assert resp.status_code == 201
        data = resp.json()
        assert "id" in data
        assert data["name"] == "IntTest Watchlist"

    async def test_add_watchlist_member(self, registry_client, seed_ids):
        """POST /watchlists/{id}/members/{company_id} — add member returns 201."""
        wl_id = seed_ids["watchlists"]["WL_01"]
        company_id = seed_ids["companies"]["XOM"]
        resp = await registry_client.post(f"/watchlists/{wl_id}/members/{company_id}")
        assert resp.status_code == 201

    async def test_list_watchlist_members(self, registry_client, seed_ids):
        """GET /watchlists/{id}/members — members with ticker and legal_name."""
        wl_id = seed_ids["watchlists"]["WL_01"]
        resp = await registry_client.get(f"/watchlists/{wl_id}/members")
        assert resp.status_code == 200
        data = resp.json()
        assert isinstance(data, list)
        assert len(data) >= 2  # AAPL and MSFT from seed
        for member in data:
            assert "ticker" in member
            assert "legal_name" in member

    async def test_duplicate_watchlist_returns_409(self, registry_client, seed_ids):
        """POST /watchlists — duplicate name returns 409."""
        payload = {"name": "Tech Leaders"}  # Already seeded
        resp = await registry_client.post("/watchlists", json=payload)
        assert resp.status_code == 409


# ---------------------------------------------------------------------------
# Task 7: Competitor and Exposure Write Paths
# ---------------------------------------------------------------------------


class TestRegistryCompetitorCRUD:
    """Competitor relationship creation, update, and soft-delete."""

    async def test_create_competitor(self, registry_client, seed_ids):
        """POST /companies/{id}/competitors — create returns 201."""
        company_id = seed_ids["companies"]["XOM"]
        competitor_id = seed_ids["companies"]["JNJ"]
        payload = {
            "company_b_id": competitor_id,
            "relationship_type": "same_sector",
            "strength": 0.4,
            "bidirectional": True,
            "source": "manual",
        }
        resp = await registry_client.post(f"/companies/{company_id}/competitors", json=payload)
        assert resp.status_code == 201
        data = resp.json()
        assert "id" in data
        assert data["relationship_type"] == "same_sector"
        assert data["strength"] == 0.4
        assert data["bidirectional"] is True

    async def test_self_referencing_competitor_returns_400(self, registry_client, seed_ids):
        """POST /companies/{id}/competitors — self-reference returns 400."""
        company_id = seed_ids["companies"]["AAPL"]
        payload = {
            "company_b_id": company_id,
            "relationship_type": "direct_rival",
            "strength": 0.5,
        }
        resp = await registry_client.post(f"/companies/{company_id}/competitors", json=payload)
        assert resp.status_code == 400

    async def test_update_competitor(self, registry_client, seed_ids):
        """PUT /companies/{id}/competitors/{rel_id} — update strength."""
        company_id = seed_ids["companies"]["AAPL"]
        competitor_id = seed_ids["companies"]["JNJ"]
        # Create a new relationship to update
        create_payload = {
            "company_b_id": competitor_id,
            "relationship_type": "overlapping_products",
            "strength": 0.3,
        }
        create_resp = await registry_client.post(
            f"/companies/{company_id}/competitors", json=create_payload
        )
        assert create_resp.status_code == 201
        rel_id = create_resp.json()["id"]
        # Update
        update_payload = {
            "company_b_id": competitor_id,
            "relationship_type": "overlapping_products",
            "strength": 0.7,
            "bidirectional": True,
            "source": "manual",
        }
        resp = await registry_client.put(
            f"/companies/{company_id}/competitors/{rel_id}", json=update_payload
        )
        assert resp.status_code == 200
        data = resp.json()
        assert data["strength"] == 0.7

    async def test_soft_delete_competitor(self, registry_client, seed_ids):
        """DELETE /companies/{id}/competitors/{rel_id} — soft-delete returns 200."""
        company_id = seed_ids["companies"]["AAPL"]
        competitor_id = seed_ids["companies"]["XOM"]
        # Create a relationship to delete
        create_payload = {
            "company_b_id": competitor_id,
            "relationship_type": "supply_chain_adjacent",
            "strength": 0.2,
        }
        create_resp = await registry_client.post(
            f"/companies/{company_id}/competitors", json=create_payload
        )
        assert create_resp.status_code == 201
        rel_id = create_resp.json()["id"]
        # Delete
        resp = await registry_client.delete(f"/companies/{company_id}/competitors/{rel_id}")
        assert resp.status_code == 200


class TestRegistryExposureCRUD:
    """Exposure profile upsert, history, and not-found handling."""

    async def test_upsert_exposure_profile(self, registry_client, seed_ids):
        """PUT /companies/{id}/exposure — upsert with version increment."""
        company_id = seed_ids["companies"]["MSFT"]  # MSFT has no exposure profile
        payload = {
            "geographic_revenue_mix": {"North America": 0.50, "Europe": 0.30, "Asia": 0.20},
            "supply_chain_regions": ["North America", "Europe"],
            "key_input_commodities": [],
            "regulatory_jurisdictions": ["US", "EU"],
            "market_position_tier": "global_leader",
            "export_dependency_pct": 0.40,
            "source": "manual",
            "confidence": 0.9,
        }
        resp = await registry_client.put(f"/companies/{company_id}/exposure", json=payload)
        assert resp.status_code == 200
        data = resp.json()
        assert data["version"] >= 1
        assert data["market_position_tier"] == "global_leader"
        assert data["geographic_revenue_mix"]["North America"] == 0.50

    async def test_exposure_history(self, registry_client, seed_ids):
        """GET /companies/{id}/exposure/history — all versions."""
        company_id = seed_ids["companies"]["AAPL"]  # AAPL has a seeded profile
        resp = await registry_client.get(f"/companies/{company_id}/exposure/history")
        assert resp.status_code == 200
        data = resp.json()
        assert isinstance(data, list)
        assert len(data) >= 1

    async def test_exposure_not_found(self, registry_client, seed_ids):
        """GET /companies/{id}/exposure — 404 for company with no profile."""
        company_id = seed_ids["companies"]["JNJ"]  # JNJ has no exposure profile
        resp = await registry_client.get(f"/companies/{company_id}/exposure")
        assert resp.status_code == 404
