from fastapi.testclient import TestClient

import services.sales_service.app as sales_module


def _headers(tenant_id: str = "tenant_pipeline") -> dict[str, str]:
    return {"X-User": "admin", "X-Role": "admin", "X-Tenant-ID": tenant_id}


def _deal_payload(seed: str = "default", **overrides: object) -> dict:
    payload = {
        "stage_id": "new_qualified_lead",
        "scenario_type": "quick_sale",
        "priority": 3,
        "title": f"Pipeline deal {seed}",
        "need_summary": "Need sales follow-up.",
        "preferred_channel": "telegram",
        "current_channel": "telegram",
    }
    payload.update(overrides)
    return payload


def _default_pipeline(client: TestClient, tenant_id: str = "tenant_pipeline") -> dict:
    response = client.get("/api/v1/pipelines", headers=_headers(tenant_id))
    assert response.status_code == 200
    pipelines = response.json()
    return next(item for item in pipelines if item["is_default"])


def _default_stages(client: TestClient, tenant_id: str = "tenant_pipeline") -> list[dict]:
    pipeline = _default_pipeline(client, tenant_id)
    response = client.get(f"/api/v1/pipelines/{pipeline['pipeline_id']}/stages", headers=_headers(tenant_id))
    assert response.status_code == 200
    return response.json()


def _create_deal(client: TestClient, tenant_id: str = "tenant_pipeline", **overrides: object) -> dict:
    response = client.post("/api/v1/deals", json=_deal_payload(tenant_id, **overrides), headers=_headers(tenant_id))
    assert response.status_code == 200
    return response.json()


def test_default_pipeline_created_for_tenant():
    client = TestClient(sales_module.app)

    pipeline = _default_pipeline(client, "tenant_pipeline_default")

    assert pipeline["pipeline_id"].startswith("pip_")
    assert pipeline["code"] == "default_sales"
    assert pipeline["name"] == "Базовая воронка продаж"
    assert pipeline["is_default"] is True
    assert pipeline["is_active"] is True


def test_default_stages_created_for_tenant():
    client = TestClient(sales_module.app)

    stages = _default_stages(client, "tenant_pipeline_stages")
    codes = [stage["code"] for stage in stages]

    assert len(stages) == 31
    assert codes[:4] == ["new_qualified_lead", "warm_lead", "hot_lead", "enrichment_required"]
    assert stages[0]["stage_id"].startswith("pst_")
    assert stages[0]["category"] == "entry"
    assert stages[0]["sort_order"] == 10
    assert next(stage for stage in stages if stage["code"] == "won")["is_terminal"] is True
    assert all(stage["is_system"] for stage in stages)


def test_create_deal_uses_default_pipeline():
    client = TestClient(sales_module.app)

    pipeline = _default_pipeline(client, "tenant_deal_pipeline")
    deal = _create_deal(client, "tenant_deal_pipeline")

    assert deal["pipeline_id"] == pipeline["pipeline_id"]
    assert deal["pipeline"]["code"] == "default_sales"


def test_create_deal_uses_real_stage_id():
    client = TestClient(sales_module.app)

    deal = _create_deal(client, "tenant_deal_stage")

    assert deal["stage_id"].startswith("pst_")
    assert deal["stage"]["code"] == "new_qualified_lead"
    assert deal["stage_id"] != "new_qualified_lead"


def test_create_deal_accepts_stage_code_input():
    client = TestClient(sales_module.app)

    deal = _create_deal(client, "tenant_deal_stage_code", stage_id=None, stage_code="offer_sent")

    assert deal["stage_id"].startswith("pst_")
    assert deal["stage"]["code"] == "offer_sent"


def test_deal_cannot_use_stage_from_another_tenant():
    client = TestClient(sales_module.app)

    foreign_stage = _default_stages(client, "tenant_stage_owner")[0]
    response = client.post(
        "/api/v1/deals",
        json=_deal_payload("foreign-stage", stage_id=foreign_stage["stage_id"]),
        headers=_headers("tenant_stage_reader"),
    )

    assert response.status_code in {400, 404}


def test_deal_cannot_use_stage_from_another_pipeline():
    client = TestClient(sales_module.app)
    tenant_id = "tenant_other_pipeline"

    pipeline = client.post(
        "/api/v1/pipelines",
        json={"code": "enterprise_sales", "name": "Enterprise Sales"},
        headers=_headers(tenant_id),
    )
    assert pipeline.status_code == 200
    stage = client.post(
        f"/api/v1/pipelines/{pipeline.json()['pipeline_id']}/stages",
        json={"code": "enterprise_entry", "name": "Enterprise Entry", "category": "entry", "sort_order": 10},
        headers=_headers(tenant_id),
    )
    assert stage.status_code == 200

    response = client.post(
        "/api/v1/deals",
        json=_deal_payload("wrong-pipeline", stage_id=stage.json()["stage_id"]),
        headers=_headers(tenant_id),
    )

    assert response.status_code == 400


def test_stage_history_uses_real_stage_ids():
    client = TestClient(sales_module.app)

    deal = _create_deal(client, "tenant_stage_history")
    changed = client.post(
        f"/api/v1/deals/{deal['deal_id']}/change-stage",
        json={"stage_id": "warm_lead", "reason": "lead warmed"},
        headers=_headers("tenant_stage_history"),
    )
    assert changed.status_code == 200
    workspace = client.get(f"/api/v1/deals/{deal['deal_id']}/workspace", headers=_headers("tenant_stage_history"))
    assert workspace.status_code == 200

    history = workspace.json()["stage_history"][0]
    assert history["to_stage_id"].startswith("pst_")
    assert history["to_stage"]["code"] == "warm_lead"
    assert history["to_stage_id"] != "warm_lead"


def test_pipeline_list_is_tenant_scoped():
    client = TestClient(sales_module.app)

    pipeline_a = _default_pipeline(client, "tenant_scope_a")
    pipeline_b = _default_pipeline(client, "tenant_scope_b")

    list_a = client.get("/api/v1/pipelines", headers=_headers("tenant_scope_a"))
    assert list_a.status_code == 200
    ids_a = {item["pipeline_id"] for item in list_a.json()}
    assert pipeline_a["pipeline_id"] in ids_a
    assert pipeline_b["pipeline_id"] not in ids_a


def test_workspace_contains_stage_object():
    client = TestClient(sales_module.app)

    deal = _create_deal(client, "tenant_workspace_stage")
    workspace = client.get(f"/api/v1/deals/{deal['deal_id']}/workspace", headers=_headers("tenant_workspace_stage"))
    assert workspace.status_code == 200
    payload = workspace.json()

    assert payload["pipeline"]["pipeline_id"] == deal["pipeline_id"]
    assert payload["stage"]["id"] == deal["stage_id"]
    assert payload["stage"]["code"] == "new_qualified_lead"
    assert payload["deal"]["stage"]["code"] == "new_qualified_lead"


def test_stage_can_be_renamed_without_changing_code():
    client = TestClient(sales_module.app)
    tenant_id = "tenant_rename_stage"

    stage = next(stage for stage in _default_stages(client, tenant_id) if stage["code"] == "new_qualified_lead")
    renamed = client.patch(
        f"/api/v1/pipeline-stages/{stage['stage_id']}",
        json={"name": "Новая заявка"},
        headers=_headers(tenant_id),
    )

    assert renamed.status_code == 200
    assert renamed.json()["name"] == "Новая заявка"
    assert renamed.json()["code"] == "new_qualified_lead"
