"""Tests for company tools."""

import pytest
import respx
from httpx import Response
from pydantic import ValidationError

from crustdata_mcp.client import CrustdataClient
from crustdata_mcp.tools.company import CompanyEnrichInput, CompanyIdentifyInput


class TestCompanyIdentifyInput:
    """Tests for CompanyIdentifyInput validation."""

    def test_valid_with_name(self):
        """Test valid input with company name."""
        params = CompanyIdentifyInput(company_name="Anthropic")
        assert params.company_name == "Anthropic"

    def test_valid_with_website(self):
        """Test valid input with company website."""
        params = CompanyIdentifyInput(company_website="anthropic.com")
        assert params.company_website == "anthropic.com"

    def test_valid_with_linkedin(self):
        """Test valid input with LinkedIn URL."""
        params = CompanyIdentifyInput(
            company_linkedin_url="https://linkedin.com/company/anthropic"
        )
        assert params.company_linkedin_url is not None

    def test_invalid_no_identifier(self):
        """Test that at least one identifier is required."""
        with pytest.raises(ValidationError, match="At least one identifier required"):
            CompanyIdentifyInput()

    def test_count_limits(self):
        """Test count parameter validation."""
        # Valid count
        params = CompanyIdentifyInput(company_name="Test", count=5)
        assert params.count == 5

        # Count too high
        with pytest.raises(ValidationError):
            CompanyIdentifyInput(company_name="Test", count=30)

        # Count too low
        with pytest.raises(ValidationError):
            CompanyIdentifyInput(company_name="Test", count=0)


class TestCompanyEnrichInput:
    """Tests for CompanyEnrichInput validation."""

    def test_valid_with_domain(self):
        """Test valid input with company domain."""
        params = CompanyEnrichInput(company_domain="anthropic.com")
        assert params.company_domain == "anthropic.com"

    def test_valid_with_id(self):
        """Test valid input with company ID."""
        params = CompanyEnrichInput(company_id="635252")
        assert params.company_id == "635252"

    def test_invalid_no_identifier(self):
        """Test that at least one identifier is required."""
        with pytest.raises(ValidationError, match="At least one identifier required"):
            CompanyEnrichInput()

    def test_with_fields(self):
        """Test input with specific fields."""
        params = CompanyEnrichInput(
            company_domain="anthropic.com",
            fields=["company_name", "company_id"],
        )
        assert params.fields == ["company_name", "company_id"]

    def test_with_valid_fields_all_categories(self):
        """Test input with valid fields from different categories."""
        params = CompanyEnrichInput(
            company_domain="anthropic.com",
            fields=[
                "company_name",
                "linkedin_profile_url",
                "hq_country",
                "headcount",
                "funding_and_investment",
                "linkedin_company_description",
            ],
        )
        assert len(params.fields) == 6

    def test_with_invalid_fields_rejects_hallucinated_names(self):
        """Test that invalid/hallucinated field names are rejected.

        This prevents LLMs from guessing field names like 'employee_count'
        instead of the correct 'headcount' or 'employee_count_range'.
        """
        with pytest.raises(ValidationError, match="Invalid fields provided"):
            CompanyEnrichInput(
                company_domain="anthropic.com",
                fields=["employee_count", "short_description"],
            )

    def test_with_invalid_fields_shows_helpful_error(self):
        """Test that error message includes valid field examples."""
        with pytest.raises(ValidationError) as exc_info:
            CompanyEnrichInput(
                company_domain="anthropic.com",
                fields=["long_description", "linkedin_company_url"],
            )
        error_msg = str(exc_info.value)
        assert "long_description" in error_msg
        assert "linkedin_company_url" in error_msg
        assert "Valid fields include" in error_msg

    def test_with_mixed_valid_invalid_fields(self):
        """Test that mix of valid and invalid fields is rejected."""
        with pytest.raises(ValidationError, match="Invalid fields provided"):
            CompanyEnrichInput(
                company_domain="anthropic.com",
                fields=["company_name", "invalid_field", "hq_country"],
            )


class TestCompanyIdentifyTool:
    """Tests for crustdata_company_identify tool."""

    @pytest.mark.asyncio
    @respx.mock
    async def test_identify_by_website_success(self):
        """Test successful company identification by website."""
        expected_response = [
            {
                "company_id": 635252,
                "company_name": "Anthropic",
                "company_website_domain": "anthropic.com",
                "linkedin_profile_url": "https://linkedin.com/company/anthropicresearch",
                "is_full_domain_match": True,
            }
        ]
        respx.post("https://api.crustdata.com/screener/identify/").mock(
            return_value=Response(200, json=expected_response)
        )

        async with CrustdataClient("test-token") as client:
            result = await client.post(
                "/screener/identify/",
                data={"query_company_website": "anthropic.com", "count": 10},
            )

        assert len(result) == 1
        assert result[0]["company_name"] == "Anthropic"
        assert result[0]["company_id"] == 635252

    @pytest.mark.asyncio
    @respx.mock
    async def test_identify_no_results(self):
        """Test identification with no matching companies."""
        respx.post("https://api.crustdata.com/screener/identify/").mock(
            return_value=Response(200, json=[])
        )

        async with CrustdataClient("test-token") as client:
            result = await client.post(
                "/screener/identify/",
                data={"query_company_name": "NonexistentCompany12345"},
            )

        assert result == []

    def test_tool_is_registered(self):
        """Test that company identify tool is registered."""
        from crustdata_mcp.server import mcp

        tools = list(mcp._tool_manager._tools.keys())
        assert "crustdata_company_identify" in tools


class TestCompanyEnrichTool:
    """Tests for crustdata_company_enrich tool."""

    @pytest.mark.asyncio
    @respx.mock
    async def test_enrich_by_domain_success(self):
        """Test successful company enrichment by domain."""
        expected_response = {
            "company_id": 635252,
            "company_name": "Anthropic",
            "linkedin_profile_url": "https://linkedin.com/company/anthropicresearch",
            "company_website_domain": "anthropic.com",
            "hq_country": "US",
        }
        respx.get("https://api.crustdata.com/screener/company").mock(
            return_value=Response(200, json=expected_response)
        )

        async with CrustdataClient("test-token") as client:
            result = await client.get(
                "/screener/company", params={"company_domain": "anthropic.com"}
            )

        assert result["company_name"] == "Anthropic"
        assert result["company_id"] == 635252

    @pytest.mark.asyncio
    @respx.mock
    async def test_enrich_multiple_companies(self):
        """Test enrichment returning multiple companies."""
        expected_response = [
            {"company_id": 1, "company_name": "Company A"},
            {"company_id": 2, "company_name": "Company B"},
        ]
        respx.get("https://api.crustdata.com/screener/company").mock(
            return_value=Response(200, json=expected_response)
        )

        async with CrustdataClient("test-token") as client:
            result = await client.get(
                "/screener/company", params={"company_name": "Company A, Company B"}
            )

        assert isinstance(result, list)
        assert len(result) == 2

    @pytest.mark.asyncio
    @respx.mock
    async def test_enrich_not_found(self):
        """Test enrichment when company not found."""
        from crustdata_mcp.client import CrustdataNotFoundError

        respx.get("https://api.crustdata.com/screener/company").mock(
            return_value=Response(404, json={"error": "Company not found"})
        )

        async with CrustdataClient("test-token") as client:
            with pytest.raises(CrustdataNotFoundError):
                await client.get(
                    "/screener/company", params={"company_domain": "nonexistent.com"}
                )

    def test_tool_is_registered(self):
        """Test that company enrich tool is registered."""
        from crustdata_mcp.server import mcp

        tools = list(mcp._tool_manager._tools.keys())
        assert "crustdata_company_enrich" in tools


class TestCompanySearchDbTool:
    """Tests for crustdata_company_search_db tool."""

    @pytest.mark.asyncio
    @respx.mock
    async def test_search_by_name_success(self):
        """Test successful company search by name."""
        expected_response = {
            "companies": [
                {"company_id": 635252, "company_name": "Anthropic"},
                {"company_id": 719012, "company_name": "Entropic"},
            ],
            "total_count": 2,
        }
        respx.post("https://api.crustdata.com/screener/companydb/search").mock(
            return_value=Response(200, json=expected_response)
        )

        async with CrustdataClient("test-token") as client:
            result = await client.post(
                "/screener/companydb/search",
                data={
                    "filters": {"filter_type": "company_name", "type": "(.)", "value": "Anthropic"},
                    "limit": 10,
                },
            )

        assert len(result["companies"]) == 2
        assert result["total_count"] == 2

    @pytest.mark.asyncio
    @respx.mock
    async def test_search_with_pagination(self):
        """Test company search with pagination cursor."""
        expected_response = {
            "companies": [{"company_id": 1}],
            "next_cursor": "abc123",
        }
        respx.post("https://api.crustdata.com/screener/companydb/search").mock(
            return_value=Response(200, json=expected_response)
        )

        async with CrustdataClient("test-token") as client:
            result = await client.post(
                "/screener/companydb/search",
                data={"filters": {}, "limit": 1},
            )

        assert result["next_cursor"] == "abc123"

    def test_tool_is_registered(self):
        """Test that company search tool is registered."""
        from crustdata_mcp.server import mcp

        tools = list(mcp._tool_manager._tools.keys())
        assert "crustdata_company_search_db" in tools


class TestLinkedInPostsTool:
    """Tests for crustdata_company_linkedin_posts tool."""

    @pytest.mark.asyncio
    @respx.mock
    async def test_search_posts_success(self):
        """Test successful LinkedIn posts search."""
        expected_response = [
            {"text": "AI safety is important...", "likes": 100},
            {"text": "Working on AI alignment...", "likes": 50},
        ]
        respx.post("https://api.crustdata.com/screener/linkedin_posts/keyword_search/").mock(
            return_value=Response(200, json=expected_response)
        )

        async with CrustdataClient("test-token") as client:
            result = await client.post(
                "/screener/linkedin_posts/keyword_search/",
                data={"keyword": "AI safety", "limit": 10},
            )

        assert len(result) == 2
        assert "AI safety" in result[0]["text"]

    def test_tool_is_registered(self):
        """Test that LinkedIn posts tool is registered."""
        from crustdata_mcp.server import mcp

        tools = list(mcp._tool_manager._tools.keys())
        assert "crustdata_company_linkedin_posts" in tools


class TestCompanyAutocompleteTool:
    """Tests for crustdata_autocomplete_company tool."""

    @pytest.mark.asyncio
    @respx.mock
    async def test_autocomplete_success(self):
        """Test successful autocomplete."""
        expected_response = {"suggestions": ["Anthropic", "Anchor", "Anthem"]}
        respx.post("https://api.crustdata.com/screener/companydb/autocomplete").mock(
            return_value=Response(200, json=expected_response)
        )

        async with CrustdataClient("test-token") as client:
            result = await client.post(
                "/screener/companydb/autocomplete",
                data={"field": "company_name", "query": "Ant"},
            )

        assert "Anthropic" in result["suggestions"]

    def test_tool_is_registered(self):
        """Test that autocomplete tool is registered."""
        from crustdata_mcp.server import mcp

        tools = list(mcp._tool_manager._tools.keys())
        assert "crustdata_autocomplete_company" in tools
