"""6F note/task/activity evidence. Zero new crm.* verbs."""
from __future__ import annotations

import pytest
from pydantic import ValidationError
from src.domain.codegen.prompt_wrapper import _app_recipes
from src.domain.connectors.catalog import CONNECTORS, get_action, slugs_implementing
from src.domain.connectors.crm_canonical import CRM_CANONICAL_MODEL, CRMObjectRef
from src.domain.connectors.invoke_capabilities import (
    CAPABILITY_CONVERSION_PATTERN,
    CRM_ACTIVITIES_PHASE_6F,
    CRM_COMPANY_FROZEN_VERBS,
    CRM_CONTACT_FROZEN_VERBS,
    CRM_DEAL_FROZEN_VERBS,
    CRM_FAMILY_PLAN,
    CRM_HYPOTHESIZED_VERBS_NOT_FROZEN,
    INVOKE_CAPABILITIES,
)
from src.domain.connectors.public_gateway import (
    PHASE_6_STATUS,
    PUBLIC_INVOCABLE_CAPABILITIES,
)
from src.domain.connectors.router import capability_router
from src.main import app

_NOTE_TASK_ACTIVITY = (
    "crm.note.create",
    "crm.task.create",
    "crm.activity.create",
)


def test_6f_refuses_canonical_note_task_activity() -> None:
    assert PHASE_6_STATUS == "6p_complete"
    assert CAPABILITY_CONVERSION_PATTERN["phase_6_status"] == "6p_complete"
    assert CAPABILITY_CONVERSION_PATTERN["next_program_slice"] == (
        "9_app_block_modernization"
    )
    assert CRM_FAMILY_PLAN["status"] == "6p_complete"
    assert CRM_FAMILY_PLAN["next_slice"] == "forms_first_class_product_domain"
    assert CRM_FAMILY_PLAN["note_decision"] == "DEFER"
    assert CRM_FAMILY_PLAN["task_decision"] == "PROVIDER_SPECIFIC_FOR_NOW"
    assert CRM_FAMILY_PLAN["activity_decision"] == "REJECT_UMBRELLA"
    assert CRM_FAMILY_PLAN["activity_verbs_frozen"] is False
    assert CRM_ACTIVITIES_PHASE_6F["new_capability_verbs"] == ()
    assert CRM_ACTIVITIES_PHASE_6F["canonical_types_frozen"] == ()
    assert CRM_ACTIVITIES_PHASE_6F["object_ref_amended"] is False
    assert CRM_ACTIVITIES_PHASE_6F["decisions"] == {
        "CRMNote": "DEFER",
        "CRMTask": "PROVIDER_SPECIFIC_FOR_NOW",
        "CRMActivity": "REJECT_UMBRELLA",
    }
    assert CRM_CANONICAL_MODEL["deferred_types"] == {
        "CRMNote": "defer",
        "CRMTask": "provider_specific_for_now",
        "CRMActivity": "reject_umbrella",
    }
    assert CRM_CANONICAL_MODEL["object_types"] == ("contact", "company", "deal")
    for verb in _NOTE_TASK_ACTIVITY:
        assert verb in CRM_HYPOTHESIZED_VERBS_NOT_FROZEN
        assert verb not in INVOKE_CAPABILITIES
        assert verb not in PUBLIC_INVOCABLE_CAPABILITIES
        assert slugs_implementing(verb) == ()
    recipes = _app_recipes()
    assert "capabilities/crm.note." not in recipes
    assert "capabilities/crm.task." not in recipes
    assert "capabilities/crm.activity." not in recipes


def test_hubspot_has_no_note_task_activity_actions() -> None:
    slugs = {action.slug for action in CONNECTORS["hubspot"].actions}
    assert CRM_ACTIVITIES_PHASE_6F["hubspot_note_actions"] == ()
    assert CRM_ACTIVITIES_PHASE_6F["hubspot_task_actions"] == ()
    assert CRM_ACTIVITIES_PHASE_6F["hubspot_activity_actions"] == ()
    for forbidden in (
        "hubspot.create_note",
        "hubspot.update_note",
        "hubspot.create_task",
        "hubspot.update_task",
        "hubspot.create_engagement",
        "hubspot.create_call",
        "hubspot.create_meeting",
        "hubspot.create_email",
    ):
        assert forbidden not in slugs
    associate = get_action("hubspot.associate_objects")
    assert associate is not None
    enum = associate[1].input_schema["properties"]["from_object_type"]["enum"]
    assert enum == list(CRM_ACTIVITIES_PHASE_6F["hubspot_association_object_types"])
    assert "notes" in enum
    assert "tasks" in enum


def test_salesforce_task_and_event_remain_provider_actions() -> None:
    slugs = {action.slug for action in CONNECTORS["salesforce"].actions}
    assert CRM_ACTIVITIES_PHASE_6F["salesforce_task_actions"] == (
        "salesforce.create_task",
    )
    assert CRM_ACTIVITIES_PHASE_6F["salesforce_event_actions"] == (
        "salesforce.create_event",
    )
    assert CRM_ACTIVITIES_PHASE_6F["salesforce_note_actions"] == ()
    assert "salesforce.create_task" in slugs
    assert "salesforce.create_event" in slugs
    for missing in (
        "salesforce.create_note",
        "salesforce.create_content_note",
        "salesforce.update_task",
        "salesforce.get_task",
        "salesforce.create_email_message",
    ):
        assert missing not in slugs
    task = get_action("salesforce.create_task")
    event = get_action("salesforce.create_event")
    assert task is not None and event is not None
    assert task[1].implements == ()
    assert event[1].implements == ()
    assert task[1].input_schema["required"] == ["fields"]
    assert "salesforce.upsert_record" in slugs
    assert "salesforce.query_soql" in slugs
    assert CRM_ACTIVITIES_PHASE_6F["generic_sobject_does_not_create_canonical"] is True


def test_object_ref_does_not_gain_note_or_task() -> None:
    CRMObjectRef(object_type="deal", external_id="006xx")
    with pytest.raises(ValidationError):
        CRMObjectRef(object_type="note", external_id="1")
    with pytest.raises(ValidationError):
        CRMObjectRef(object_type="task", external_id="1")
    with pytest.raises(ValidationError):
        CRMObjectRef(object_type="activity", external_id="1")


def test_no_private_note_task_activity_routes() -> None:
    paths = {getattr(route, "path", "") for route in capability_router.routes}
    app_paths = {getattr(route, "path", "") for route in app.routes}
    for verb in _NOTE_TASK_ACTIVITY:
        expected = f"/api/projects/{{project_id}}/capabilities/{verb}"
        assert expected not in paths
        assert expected not in app_paths
    for verb in (*CRM_CONTACT_FROZEN_VERBS, *CRM_COMPANY_FROZEN_VERBS, *CRM_DEAL_FROZEN_VERBS):
        assert verb in INVOKE_CAPABILITIES
