"""Custom fields tests — plugin-defined custom fields on contacts."""

from __future__ import annotations

import pytest
from httpx import AsyncClient

from tests.conftest import ORIGIN_HEADER, login_client, seed_tenant_and_users


@pytest.mark.asyncio
class TestCustomFieldsGet:
    """GET /api/v1/contacts/{id}/custom-fields"""

    async def test_get_custom_fields_returns_200(self, client: AsyncClient, db_session):
        """GET custom fields for a contact returns 200 with merged definitions."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        # Create a contact first
        resp = await client.post(
            "/api/v1/contacts",
            json={"type": "company", "name": "Test Corp", "displayname": "Test Corp"},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 201
        contact_id = resp.json()["id"]

        resp = await client.get(
            f"/api/v1/contacts/{contact_id}/custom-fields",
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 200
        data = resp.json()
        assert "fields" in data
        assert isinstance(data["fields"], list)

    async def test_get_custom_fields_invalid_uuid_returns_400(self, client: AsyncClient, db_session):
        """GET custom fields with invalid UUID returns 400."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.get(
            "/api/v1/contacts/not-a-uuid/custom-fields",
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 400

    async def test_get_custom_fields_not_found_returns_404(self, client: AsyncClient, db_session):
        """GET custom fields for non-existent contact returns 404."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.get(
            "/api/v1/contacts/00000000-0000-0000-0000-000000000000/custom-fields",
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 404


@pytest.mark.asyncio
class TestCustomFieldsUpdate:
    """PATCH /api/v1/contacts/{id}/custom-fields"""

    async def test_update_custom_fields_returns_200(self, client: AsyncClient, db_session):
        """PATCH custom fields stores values in contacts.custom JSONB."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        # Create a contact
        resp = await client.post(
            "/api/v1/contacts",
            json={"type": "company", "name": "Custom Corp", "displayname": "Custom Corp"},
            headers=ORIGIN_HEADER,
        )
        contact_id = resp.json()["id"]

        # Update custom fields (empty values is valid since no plugin defines fields)
        resp = await client.patch(
            f"/api/v1/contacts/{contact_id}/custom-fields",
            json={"values": {"test_field": "test_value"}},
            headers=ORIGIN_HEADER,
        )
        # Without plugin definitions, unknown fields should be rejected
        assert resp.status_code == 400

    async def test_update_custom_fields_empty_values_returns_200(self, client: AsyncClient, db_session):
        """PATCH custom fields with empty values dict returns 200."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.post(
            "/api/v1/contacts",
            json={"type": "company", "name": "Empty Corp", "displayname": "Empty Corp"},
            headers=ORIGIN_HEADER,
        )
        contact_id = resp.json()["id"]

        resp = await client.patch(
            f"/api/v1/contacts/{contact_id}/custom-fields",
            json={"values": {}},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 200
        assert "fields" in resp.json()

    async def test_update_custom_fields_not_found_returns_404(self, client: AsyncClient, db_session):
        """PATCH custom fields for non-existent contact returns 404."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.patch(
            "/api/v1/contacts/00000000-0000-0000-0000-000000000000/custom-fields",
            json={"values": {}},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 404


@pytest.mark.asyncio
class TestCustomFieldDefinition:
    """Test CustomFieldDefinition model in manifest."""

    async def test_custom_field_definition_creation(self):
        """CustomFieldDefinition can be created with valid field types."""
        from app.plugins.manifest import CustomFieldDefinition

        cf = CustomFieldDefinition(
            name="lead_source",
            label="Lead Source",
            label_key="custom.leadSource",
            field_type="select",
            options=["website", "referral", "cold_call"],
            required=False,
            entity="contact",
        )
        assert cf.name == "lead_source"
        assert cf.field_type == "select"
        assert len(cf.options) == 3

    async def test_custom_field_definition_invalid_type_raises(self):
        """CustomFieldDefinition rejects invalid field_type."""
        from app.plugins.manifest import CustomFieldDefinition
        from pydantic import ValidationError

        with pytest.raises(ValidationError):
            CustomFieldDefinition(
                name="bad_field",
                field_type="invalid_type",
            )

    async def test_plugin_manifest_with_custom_fields(self):
        """PluginManifest accepts custom_fields list."""
        from app.plugins.manifest import PluginManifest, CustomFieldDefinition

        manifest = PluginManifest(
            name="test_plugin",
            version="1.0.0",
            display_name="Test Plugin",
            custom_fields=[
                CustomFieldDefinition(
                    name="score",
                    label="Score",
                    field_type="number",
                    entity="contact",
                ),
            ],
        )
        assert len(manifest.custom_fields) == 1
        assert manifest.custom_fields[0].name == "score"
