from __future__ import annotations

import json
import re

import pytest

pytest.importorskip("rich_click")
pytest.importorskip("rich")
pytest.importorskip("platformdirs")

try:
    import respx
except ModuleNotFoundError:  # pragma: no cover - optional dev dependency
    respx = None  # type: ignore[assignment]

from click.testing import CliRunner
from httpx import Response

from affinity.cli.main import cli

if respx is None:  # pragma: no cover
    pytest.skip("respx is not installed", allow_module_level=True)


def test_company_get_by_id_minimal(respx_mock: respx.MockRouter) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(
            200,
            json={"id": 123, "name": "Acme Corp", "domain": "acme.com", "domains": ["acme.com"]},
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["--json", "company", "get", "123"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    payload = json.loads(result.output.strip())
    assert payload["ok"] is True
    assert payload["command"]["name"] == "company get"
    assert payload["data"]["company"]["id"] == 123
    assert payload["meta"]["resolved"]["company"]["source"] == "id"


def test_company_get_accepts_affinity_dot_com_url(respx_mock: respx.MockRouter) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(
            200,
            json={"id": 123, "name": "Acme Corp", "domain": "acme.com", "domains": ["acme.com"]},
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["--json", "company", "get", "https://mydomain.affinity.com/companies/123"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    payload = json.loads(result.output.strip())
    assert payload["ok"] is True
    assert payload["meta"]["resolved"]["company"]["source"] == "url"
    assert payload["meta"]["resolved"]["company"]["companyId"] == 123


def test_company_get_field_union_uses_field_ids(respx_mock: respx.MockRouter) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/fields").mock(
        return_value=Response(
            200,
            json={
                "data": [
                    {
                        "id": "dealroom-url",
                        "name": "Dealroom.co URL",
                        "type": "enriched",
                        "valueType": "text",
                        "allowsMultiple": False,
                    },
                    {
                        "id": "field-1",
                        "name": "Stage",
                        "type": "global",
                        "valueType": "dropdown",
                        "allowsMultiple": False,
                    },
                ]
            },
        )
    )

    route = respx_mock.get(
        "https://api.affinity.co/v2/companies/123?fieldIds=dealroom-url&fieldIds=field-1"
    ).mock(
        return_value=Response(
            200,
            json={
                "id": 123,
                "name": "Acme Corp",
                "domain": "acme.com",
                "domains": ["acme.com"],
                "fields": [
                    {
                        "id": "dealroom-url",
                        "type": "enriched",
                        "name": "Dealroom.co URL",
                        "value": {"type": "text", "data": "https://dealroom.co/acme"},
                    },
                    {
                        "id": "field-1",
                        "type": "global",
                        "name": "Stage",
                        "value": {"type": "dropdown", "data": {"id": 1, "text": "Seed"}},
                    },
                ],
            },
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        [
            "--json",
            "company",
            "get",
            "123",
            "--field",
            "Dealroom.co URL",
            "--field-type",
            "global",
        ],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    payload = json.loads(result.output.strip())
    assert payload["ok"] is True
    selection = payload["meta"]["resolved"]["fieldSelection"]
    assert "fieldIds" in selection
    assert selection["fieldTypes"] == ["global"]

    assert route.called
    req = route.calls[0].request
    field_ids = req.url.params.get_list("fieldIds")
    assert "dealroom-url" in field_ids
    assert "field-1" in field_ids
    assert req.url.params.get_list("fieldTypes") == []


def test_company_get_expand_list_entries_filtered_by_list_id(respx_mock: respx.MockRouter) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(
            200,
            json={"id": 123, "name": "Acme Corp", "domain": "acme.com", "domains": ["acme.com"]},
        )
    )
    respx_mock.get("https://api.affinity.co/v2/companies/123/list-entries?limit=100").mock(
        return_value=Response(
            200,
            json={
                "data": [
                    {"id": 1, "listId": 10, "createdAt": "2020-01-01T00:00:00Z", "fields": {}},
                    {"id": 2, "listId": 11, "createdAt": "2020-01-01T00:00:00Z", "fields": {}},
                ]
            },
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["--json", "company", "get", "123", "--expand", "list-entries", "--list", "10"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    payload = json.loads(result.output.strip())
    assert payload["ok"] is True
    entries = payload["data"]["listEntries"]
    assert [e["id"] for e in entries] == [1]
    assert payload["meta"]["resolved"]["list"]["listId"] == 10


def test_company_get_expand_people_v1(respx_mock: respx.MockRouter) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(
            200,
            json={"id": 123, "name": "Acme Corp", "domain": "acme.com", "domains": ["acme.com"]},
        )
    )
    respx_mock.get("https://api.affinity.co/organizations/123").mock(
        return_value=Response(200, json={"id": 123, "person_ids": [11, 22]})
    )
    respx_mock.get("https://api.affinity.co/persons/11").mock(
        return_value=Response(
            200,
            json={
                "id": 11,
                "first_name": "Ada",
                "last_name": "Lovelace",
                "primary_email": "ada@example.com",
                "type": 0,
            },
        )
    )
    respx_mock.get("https://api.affinity.co/persons/22").mock(
        return_value=Response(
            200,
            json={
                "id": 22,
                "first_name": "Alan",
                "last_name": "Turing",
                "primary_email": "alan@example.com",
                "type": 1,
            },
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["--json", "company", "get", "123", "--expand", "people"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    payload = json.loads(result.output.strip())
    assert payload["ok"] is True
    assert payload["data"]["people"] == [
        {
            "id": 11,
            "name": "Ada Lovelace",
            "primaryEmail": "ada@example.com",
            "type": "external",
        },
        {
            "id": 22,
            "name": "Alan Turing",
            "primaryEmail": "alan@example.com",
            "type": "internal",
        },
    ]
    assert "people" in payload["meta"]["resolved"]["expand"]


def test_company_get_list_filter_requires_expand(respx_mock: respx.MockRouter) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(200, json={"id": 123, "name": "Acme Corp"})
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["--json", "company", "get", "123", "--list", "10"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 2
    payload = json.loads(result.output.strip())
    assert payload["ok"] is False
    assert payload["error"]["type"] == "usage_error"


def test_company_get_human_output_hides_envelope_pagination(respx_mock: respx.MockRouter) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(
            200,
            json={"id": 123, "name": "Acme Corp", "domain": "acme.com", "domains": ["acme.com"]},
        )
    )
    respx_mock.get("https://api.affinity.co/v2/companies/123/lists?limit=100").mock(
        return_value=Response(
            200,
            json={
                "data": [{"id": 1, "name": "Dealflow", "isPublic": False}],
                "pagination": {"prevUrl": None, "nextUrl": None},
            },
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["company", "get", "123", "--expand", "lists"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    assert "Acme Corp" in result.output
    assert "Dealflow" in result.output
    assert "pagination" not in result.output
    assert "nextUrl" not in result.output


def test_company_get_human_output_shows_fields_when_requested(respx_mock: respx.MockRouter) -> None:
    url_re = re.compile(r"https://api\.affinity\.co/v2/companies/123(\?.*)?$")
    respx_mock.get(url_re).mock(
        return_value=Response(
            200,
            json={
                "id": 123,
                "name": "Acme Corp",
                "domain": "acme.com",
                "fields": [
                    {
                        "id": "dealroom-year-founded",
                        "type": "enriched",
                        "name": "Year Founded",
                        "value": {"type": "number", "data": 2019.0},
                    }
                ],
            },
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["company", "get", "123", "--all-fields"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    assert "Company" in result.output
    assert "Fields" in result.output
    assert "Year Founded" in result.output
    assert "2019" in result.output


def test_company_get_human_output_list_entries_default_is_count_only(
    respx_mock: respx.MockRouter,
) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(
            200,
            json={"id": 123, "name": "Acme Corp", "domain": "acme.com", "domains": ["acme.com"]},
        )
    )
    respx_mock.get("https://api.affinity.co/v2/companies/123/list-entries?limit=100").mock(
        return_value=Response(
            200,
            json={
                "data": [
                    {
                        "id": 135563331,
                        "listId": 41780,
                        "creatorId": 116834779,
                        "createdAt": "2023-08-06T11:39:40Z",
                        "fields": [
                            {
                                "id": "source-of-introduction",
                                "type": "relationship-intelligence",
                                "enrichmentSource": None,
                                "name": "Source of Introduction",
                                "value": {
                                    "type": "person",
                                    "data": {
                                        "id": 26229794,
                                        "firstName": "Yaniv",
                                        "lastName": "Golan",
                                        "primaryEmailAddress": "yaniv@example.com",
                                        "type": "internal",
                                    },
                                },
                            },
                            {
                                "id": "affinity-data-number-of-employees",
                                "type": "enriched",
                                "enrichmentSource": "affinity-data",
                                "name": "Number of Employees",
                                "value": {"type": "number", "data": 15.0},
                            },
                        ],
                    }
                ],
                "pagination": {"prevUrl": None, "nextUrl": None},
            },
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["company", "get", "123", "--expand", "list-entries"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    assert "List Entries" in result.output
    assert "fieldsCount" in result.output
    assert "Source of Introduction" not in result.output
    assert "{'id':" not in result.output


def test_company_get_human_output_show_list_entry_fields_requires_max_results(
    respx_mock: respx.MockRouter,
) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(200, json={"id": 123, "name": "Acme Corp"})
    )
    respx_mock.get("https://api.affinity.co/v2/companies/123/list-entries?limit=100").mock(
        return_value=Response(200, json={"data": []})
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        ["company", "get", "123", "--expand", "list-entries", "--show-list-entry-fields"],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 2


def test_company_get_human_output_show_list_entry_fields_renders_fields_tables(
    respx_mock: respx.MockRouter,
) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(
            200,
            json={"id": 123, "name": "Acme Corp", "domain": "acme.com", "domains": ["acme.com"]},
        )
    )
    respx_mock.get("https://api.affinity.co/v2/lists/41780").mock(
        return_value=Response(
            200,
            json={
                "id": 41780,
                "name": "Dealflow",
                "type": "company",
                "isPublic": False,
                "ownerId": 1,
                "creatorId": 1,
                "listSize": 0,
            },
        )
    )
    respx_mock.get("https://api.affinity.co/v2/companies/123/list-entries?limit=1").mock(
        return_value=Response(
            200,
            json={
                "data": [
                    {
                        "id": 135563331,
                        "listId": 41780,
                        "creatorId": 116834779,
                        "createdAt": "2023-08-06T11:39:40Z",
                        "fields": [
                            {
                                "id": "field-1",
                                "type": "list",
                                "enrichmentSource": None,
                                "name": "Status",
                                "value": {
                                    "type": "ranked-dropdown",
                                    "data": {
                                        "dropdownOptionId": 1,
                                        "text": "Intro Meeting",
                                        "rank": 2,
                                        "color": "orange",
                                    },
                                },
                            },
                            {
                                "id": "source-of-introduction",
                                "type": "relationship-intelligence",
                                "enrichmentSource": None,
                                "name": "Source of Introduction",
                                "value": {
                                    "type": "person",
                                    "data": {
                                        "id": 26229794,
                                        "firstName": "Yaniv",
                                        "lastName": "Golan",
                                        "primaryEmailAddress": "yaniv@example.com",
                                        "type": "internal",
                                    },
                                },
                            },
                        ],
                        "pagination": {"prevUrl": None, "nextUrl": None},
                    }
                ],
                "pagination": {"prevUrl": None, "nextUrl": None},
            },
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        [
            "company",
            "get",
            "123",
            "--expand",
            "list-entries",
            "--max-results",
            "1",
            "--show-list-entry-fields",
        ],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    assert "List Entries" in result.output
    assert "fieldsCount" in result.output
    normalized = re.sub(r"[│┃\s]+", " ", result.output)
    assert "List Entry 135563331" in normalized
    assert "Status" in normalized
    assert "Intro Meeting" in normalized
    assert "Some non-list fields hidden" in result.output


def test_company_get_show_list_entry_fields_scope_hint_suppressed_when_all_list(
    respx_mock: respx.MockRouter,
) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(200, json={"id": 123, "name": "Acme Corp"})
    )
    respx_mock.get("https://api.affinity.co/v2/lists/41780").mock(
        return_value=Response(
            200,
            json={
                "id": 41780,
                "name": "Dealflow",
                "type": "company",
                "isPublic": False,
                "ownerId": 1,
                "creatorId": 1,
                "listSize": 0,
            },
        )
    )
    respx_mock.get("https://api.affinity.co/v2/companies/123/list-entries?limit=1").mock(
        return_value=Response(
            200,
            json={
                "data": [
                    {
                        "id": 135563331,
                        "listId": 41780,
                        "creatorId": 116834779,
                        "createdAt": "2023-08-06T11:39:40Z",
                        "fields": [
                            {
                                "id": "field-1",
                                "type": "list",
                                "enrichmentSource": None,
                                "name": "Status",
                                "value": {"type": "text", "data": "Active"},
                            }
                        ],
                    }
                ],
                "pagination": {"prevUrl": None, "nextUrl": None},
            },
        )
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        [
            "company",
            "get",
            "123",
            "--expand",
            "list-entries",
            "--max-results",
            "1",
            "--show-list-entry-fields",
        ],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 0
    assert "Some non-list fields hidden" not in result.output


def test_company_get_list_entry_fields_scope_requires_show(
    respx_mock: respx.MockRouter,
) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(200, json={"id": 123, "name": "Acme Corp"})
    )
    respx_mock.get("https://api.affinity.co/v2/companies/123/list-entries?limit=100").mock(
        return_value=Response(200, json={"data": []})
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        [
            "company",
            "get",
            "123",
            "--expand",
            "list-entries",
            "--list-entry-fields-scope",
            "all",
        ],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 2


def test_company_get_human_output_list_entry_field_requires_list_for_names(
    respx_mock: respx.MockRouter,
) -> None:
    respx_mock.get("https://api.affinity.co/v2/companies/123").mock(
        return_value=Response(200, json={"id": 123, "name": "Acme Corp"})
    )
    respx_mock.get("https://api.affinity.co/v2/companies/123/list-entries?limit=100").mock(
        return_value=Response(200, json={"data": []})
    )

    runner = CliRunner()
    result = runner.invoke(
        cli,
        [
            "company",
            "get",
            "123",
            "--expand",
            "list-entries",
            "--list-entry-field",
            "Stage Name",
        ],
        env={"AFFINITY_API_KEY": "test-key"},
    )
    assert result.exit_code == 2
