"""Tests for Pydantic models."""

import pytest
from pydantic import ValidationError

from crustdata_mcp.models.common import (
    COMPANY_ENRICH_VALID_FIELDS,
    ApiResponse,
    CompanyEnrichField,
    FilterCondition,
    FilterGroup,
    PaginationParams,
    SortOption,
    validate_company_enrich_fields,
)


class TestFilterCondition:
    """Tests for FilterCondition model."""

    def test_basic_filter(self):
        """Test creating a basic filter condition."""
        filter_cond = FilterCondition(filter_type="hq_country", value="US")
        assert filter_cond.filter_type == "hq_country"
        assert filter_cond.type == "="
        assert filter_cond.value == "US"

    def test_filter_with_operator(self):
        """Test filter with custom operator."""
        filter_cond = FilterCondition(filter_type="employee_count", type=">", value=100)
        assert filter_cond.type == ">"
        assert filter_cond.value == 100

    def test_filter_with_list_value(self):
        """Test filter with list value for 'in' operator."""
        filter_cond = FilterCondition(filter_type="industry", type="in", value=["Tech", "Finance"])
        assert filter_cond.type == "in"
        assert filter_cond.value == ["Tech", "Finance"]

    def test_filter_invalid_operator(self):
        """Test that invalid operator raises validation error."""
        with pytest.raises(ValidationError):
            FilterCondition(filter_type="hq_country", type="invalid", value="US")


class TestFilterGroup:
    """Tests for FilterGroup model."""

    def test_basic_group(self):
        """Test creating a basic filter group."""
        group = FilterGroup(
            op="AND",
            conditions=[
                FilterCondition(filter_type="hq_country", value="US"),
                FilterCondition(filter_type="industry", value="Tech"),
            ],
        )
        assert group.op == "AND"
        assert len(group.conditions) == 2

    def test_nested_group(self):
        """Test nested filter groups."""
        inner_group = FilterGroup(
            op="OR",
            conditions=[
                FilterCondition(filter_type="hq_country", value="US"),
                FilterCondition(filter_type="hq_country", value="UK"),
            ],
        )
        outer_group = FilterGroup(
            op="AND",
            conditions=[
                inner_group,
                FilterCondition(filter_type="industry", value="Tech"),
            ],
        )
        assert outer_group.op == "AND"
        assert len(outer_group.conditions) == 2

    def test_empty_group(self):
        """Test creating an empty filter group."""
        group = FilterGroup()
        assert group.op == "AND"
        assert group.conditions == []


class TestSortOption:
    """Tests for SortOption model."""

    def test_default_sort_order(self):
        """Test default sort order is ascending."""
        sort = SortOption(column="company_name")
        assert sort.column == "company_name"
        assert sort.order == "asc"

    def test_descending_sort(self):
        """Test descending sort order."""
        sort = SortOption(column="employee_count", order="desc")
        assert sort.order == "desc"

    def test_invalid_sort_order(self):
        """Test that invalid sort order raises validation error."""
        with pytest.raises(ValidationError):
            SortOption(column="company_name", order="invalid")


class TestPaginationParams:
    """Tests for PaginationParams model."""

    def test_default_values(self):
        """Test default pagination values."""
        params = PaginationParams()
        assert params.page is None
        assert params.limit is None
        assert params.cursor is None
        assert params.offset is None

    def test_page_and_limit(self):
        """Test page and limit parameters."""
        params = PaginationParams(page=2, limit=50)
        assert params.page == 2
        assert params.limit == 50

    def test_cursor_pagination(self):
        """Test cursor-based pagination."""
        params = PaginationParams(cursor="eyJpZCI6IDEwMDB9", limit=100)
        assert params.cursor == "eyJpZCI6IDEwMDB9"
        assert params.limit == 100

    def test_page_minimum(self):
        """Test that page must be at least 1."""
        with pytest.raises(ValidationError):
            PaginationParams(page=0)

    def test_limit_maximum(self):
        """Test that limit cannot exceed 1000."""
        with pytest.raises(ValidationError):
            PaginationParams(limit=1001)

    def test_offset_minimum(self):
        """Test that offset must be non-negative."""
        with pytest.raises(ValidationError):
            PaginationParams(offset=-1)


class TestApiResponse:
    """Tests for ApiResponse model."""

    def test_success_response(self):
        """Test successful response."""
        response = ApiResponse(
            success=True, data={"company_id": 123}, message="Company found", total_count=1
        )
        assert response.success is True
        assert response.data == {"company_id": 123}
        assert response.message == "Company found"
        assert response.total_count == 1

    def test_minimal_response(self):
        """Test minimal response with defaults."""
        response = ApiResponse()
        assert response.success is True
        assert response.data is None
        assert response.message is None

    def test_paginated_response(self):
        """Test paginated response with cursor."""
        response = ApiResponse(
            data=[{"id": 1}, {"id": 2}], total_count=100, next_cursor="abc123"
        )
        assert response.next_cursor == "abc123"
        assert response.total_count == 100


class TestCompanyEnrichField:
    """Tests for CompanyEnrichField enum."""

    def test_enum_values_are_strings(self):
        """Test that enum values are strings."""
        assert CompanyEnrichField.COMPANY_NAME.value == "company_name"
        assert CompanyEnrichField.LINKEDIN_PROFILE_URL.value == "linkedin_profile_url"
        assert CompanyEnrichField.HEADCOUNT.value == "headcount"

    def test_enum_str_conversion(self):
        """Test that enum converts to string properly."""
        assert str(CompanyEnrichField.HQ_COUNTRY) == "hq_country"

    def test_valid_fields_set_contains_all_enum_values(self):
        """Test that COMPANY_ENRICH_VALID_FIELDS contains all enum values."""
        for field in CompanyEnrichField:
            assert field.value in COMPANY_ENRICH_VALID_FIELDS

    def test_expected_fields_exist(self):
        """Test that common expected fields exist in the enum."""
        expected_fields = [
            "company_id",
            "company_name",
            "linkedin_profile_url",
            "linkedin_company_description",
            "headcount",
            "employee_count_range",
            "hq_country",
            "headquarters",
            "funding_and_investment",
            "founders",
            "cxos",
        ]
        for field in expected_fields:
            assert field in COMPANY_ENRICH_VALID_FIELDS, f"Missing expected field: {field}"


class TestValidateCompanyEnrichFields:
    """Tests for validate_company_enrich_fields function."""

    def test_all_valid_fields(self):
        """Test validation with all valid fields."""
        fields = ["company_name", "hq_country", "headcount"]
        valid, invalid = validate_company_enrich_fields(fields)
        assert valid == fields
        assert invalid == []

    def test_all_invalid_fields(self):
        """Test validation with all invalid fields."""
        fields = ["employee_count", "short_description", "invalid_field"]
        valid, invalid = validate_company_enrich_fields(fields)
        assert valid == []
        assert set(invalid) == set(fields)

    def test_mixed_valid_invalid_fields(self):
        """Test validation with mix of valid and invalid fields."""
        fields = ["company_name", "employee_count", "hq_country", "bad_field"]
        valid, invalid = validate_company_enrich_fields(fields)
        assert set(valid) == {"company_name", "hq_country"}
        assert set(invalid) == {"employee_count", "bad_field"}

    def test_empty_list(self):
        """Test validation with empty list."""
        valid, invalid = validate_company_enrich_fields([])
        assert valid == []
        assert invalid == []

    def test_common_hallucinated_fields_are_invalid(self):
        """Test that commonly hallucinated field names are correctly identified as invalid."""
        hallucinated_fields = [
            "employee_count",  # Should be headcount or employee_count_range
            "short_description",  # Should be linkedin_company_description
            "long_description",  # Should be linkedin_company_description
            "linkedin_company_url",  # Should be linkedin_profile_url
            "description",  # Should be linkedin_company_description
            "employees",  # Should be headcount
            "funding",  # Should be funding_and_investment
        ]
        valid, invalid = validate_company_enrich_fields(hallucinated_fields)
        assert valid == []
        assert set(invalid) == set(hallucinated_fields)
