"""
A contract's real total_amount (line items + HST) never got copied onto its
linked Opportunity.estimated_value — so the Pipeline card kept showing the
rough guess captured at inquiry time even after a real contract with a known
total existed, while the Contract detail page showed the correct total.
Fixed in ContractService.create()/update_draft() via _sync_opportunity_
estimated_value().
"""
from __future__ import annotations

from decimal import Decimal

import pytest
from httpx import AsyncClient

CONTRACTS_URL = "/api/v1/sales/contracts"
OPPS_URL = "/api/v1/sales/opportunities"


def _headers(token: str, tenant_id) -> dict:
    return {"Authorization": f"Bearer {token}", "X-Tenant-ID": str(tenant_id)}


async def _create_opportunity(client: AsyncClient, token: str, tenant_id, estimated_value=1800) -> str:
    resp = await client.post(
        OPPS_URL,
        json={"family_name": "Sync Test Family", "care_type": "pre_need", "estimated_value": estimated_value},
        headers=_headers(token, tenant_id),
    )
    assert resp.status_code == 201, resp.text
    return resp.json()["data"]["id"]


async def _get_opportunity(client: AsyncClient, token: str, tenant_id, opp_id: str) -> dict:
    resp = await client.get(f"{OPPS_URL}/{opp_id}", headers=_headers(token, tenant_id))
    assert resp.status_code == 200, resp.text
    return resp.json()["data"]


@pytest.mark.asyncio
async def test_create_contract_syncs_opportunity_estimated_value(
    client: AsyncClient, admin_token: str, test_account,
):
    """POST /contracts with an opportunity_id → Opportunity.estimated_value
    is overwritten with the new contract's real total_amount (line items + 13% HST)."""
    opp_id = await _create_opportunity(client, admin_token, test_account.id, estimated_value=1800)

    resp = await client.post(
        CONTRACTS_URL,
        json={
            "opportunity_id": opp_id,
            "contract_type": "pre_need",
            "purchaser_name": "Sync Test Family",
            "purchaser_email": "sync@example.ca",
            "payment_plan_type": "full",
            "line_items": [{"description": "Plot A-1", "quantity": 1, "unit_price": "4000.00"}],
        },
        headers=_headers(admin_token, test_account.id),
    )
    assert resp.status_code == 201, resp.text
    contract_total = Decimal(resp.json()["data"]["total_amount"])
    assert contract_total == Decimal("4520.00")  # 4000 * 1.13

    opp = await _get_opportunity(client, admin_token, test_account.id, opp_id)
    assert Decimal(str(opp["estimated_value"])) == contract_total


@pytest.mark.asyncio
async def test_create_contract_without_opportunity_does_not_error(
    client: AsyncClient, admin_token: str, test_account,
):
    """POST /contracts with no opportunity_id → nothing to sync, still succeeds."""
    resp = await client.post(
        CONTRACTS_URL,
        json={
            "contract_type": "pre_need",
            "purchaser_name": "Standalone Buyer",
            "purchaser_email": "standalone@example.ca",
            "payment_plan_type": "full",
            "line_items": [{"description": "Plot B-2", "quantity": 1, "unit_price": "1000.00"}],
        },
        headers=_headers(admin_token, test_account.id),
    )
    assert resp.status_code == 201, resp.text


@pytest.mark.asyncio
async def test_update_draft_contract_resyncs_estimated_value_on_line_item_change(
    client: AsyncClient, admin_token: str, test_account,
):
    """PATCH a draft contract's line items → total_amount AND the linked
    opportunity's estimated_value both update to the new total."""
    opp_id = await _create_opportunity(client, admin_token, test_account.id, estimated_value=1800)

    create_resp = await client.post(
        CONTRACTS_URL,
        json={
            "opportunity_id": opp_id,
            "contract_type": "pre_need",
            "purchaser_name": "Sync Test Family",
            "purchaser_email": "sync@example.ca",
            "payment_plan_type": "full",
            "line_items": [{"description": "Plot A-1", "quantity": 1, "unit_price": "4000.00"}],
        },
        headers=_headers(admin_token, test_account.id),
    )
    assert create_resp.status_code == 201, create_resp.text
    contract_id = create_resp.json()["data"]["id"]

    update_resp = await client.patch(
        f"{CONTRACTS_URL}/{contract_id}",
        json={"line_items": [{"description": "Plot A-1 (revised)", "quantity": 1, "unit_price": "6000.00"}]},
        headers=_headers(admin_token, test_account.id),
    )
    assert update_resp.status_code == 200, update_resp.text
    new_total = Decimal(update_resp.json()["data"]["total_amount"])
    assert new_total == Decimal("6780.00")  # 6000 * 1.13

    opp = await _get_opportunity(client, admin_token, test_account.id, opp_id)
    assert Decimal(str(opp["estimated_value"])) == new_total
