from datetime import UTC, datetime

from fastapi.testclient import TestClient

from zbt.commands.seed import build_seed_manifest
from zbt.core.config import Settings
from zbt.core.passwords import PasswordService
from zbt.domains.agent.repository import InMemoryAgentRepository
from zbt.domains.attribution.models import (
    OrderAttribution,
    PromotionCode,
    Salesperson,
)
from zbt.domains.attribution.repository import InMemoryAttributionRepository
from zbt.domains.attribution.service import AttributionService
from zbt.domains.catalog.repository import InMemoryCatalogRepository
from zbt.domains.enrollment.models import EnrollmentOrder
from zbt.domains.enrollment.repository import InMemoryEnrollmentRepository
from zbt.domains.identity.models import AdminUser, H5User
from zbt.domains.identity.repository import InMemoryIdentityRepository
from zbt.main import create_app

NOW = datetime(2026, 7, 26, 9, tzinfo=UTC)


def _seed_attribution(
    repository: InMemoryAttributionRepository,
    *,
    admin_user_id: str = "01ADMIN0000000000000000001",
) -> tuple[Salesperson, PromotionCode]:
    salesperson = Salesperson(
        id="01SALES0000000000000000001",
        admin_user_id=admin_user_id,
        code="SALES-A",
        name="业务员A",
        status="ACTIVE",
        created_at=NOW,
    )
    code = PromotionCode(
        id="01PROMO0000000000000000001",
        code="ZBT-SALES-A",
        salesperson_id=salesperson.id,
        channel="GROUND_PROMOTION",
        status="ACTIVE",
        created_at=NOW,
    )
    repository.save_salesperson(salesperson)
    repository.save_promotion_code(code)
    return salesperson, code


def _order(order_id: str, user_id: str, amount_cents: int = 19900) -> EnrollmentOrder:
    return EnrollmentOrder(
        id=order_id,
        order_no=f"ORD-{order_id[-4:]}",
        user_id=user_id,
        quote_id=f"QUOTE-{order_id}"[-26:],
        draft_id=f"DRAFT-{order_id}"[-26:],
        confirmation_id=f"CONFIRM-{order_id}"[-26:],
        idempotency_key=f"IDEMPOTENCY-{order_id}",
        product_id="01PRODUCT00000000000000001",
        product_version_id="01VERSION00000000000000001",
        plan_id="01PLAN0000000000000000001",
        applicant_snapshot={
            "name": "周明远",
            "id_no": "510104198801011234",
        },
        insured_snapshot={
            "name": "周建国",
            "id_no": "510104196001011234",
        },
        amount_cents=amount_cents,
        currency="CNY",
        status="ISSUED",
        created_at=NOW,
    )


def test_first_touch_attribution_is_stable_and_order_snapshot_is_idempotent() -> None:
    repository = InMemoryAttributionRepository()
    salesperson, code = _seed_attribution(repository)
    service = AttributionService(repository, lambda: NOW)
    user = H5User(
        id="01H5USER000000000000000001",
        mobile="18800000001",
        mobile_masked="188****0001",
        display_name="体验用户",
        status="ACTIVE",
        created_at=NOW,
    )

    first = service.capture_visit(user, code.code)
    second = service.capture_visit(user, code.code)
    order = _order("01ORDER0000000000000000001", user.id)
    service.record_order(order)
    service.record_order(order)

    assert first["first_touch"] is True
    assert second["first_touch"] is False
    lead = repository.get_lead_by_user(user.id)
    assert lead is not None
    assert lead.salesperson_id == salesperson.id
    assert lead.visit_count == 2
    performance = service.performance(salesperson.admin_user_id)
    assert performance["visit_count"] == 2
    assert performance["lead_count"] == 1
    assert performance["order_count"] == 1
    assert performance["premium_cents"] == 19900
    assert service.order_ids(salesperson.admin_user_id) == {order.id}


def test_h5_referral_login_and_admin_self_scope_form_a_closed_loop() -> None:
    identities = InMemoryIdentityRepository()
    admin = AdminUser(
        id="01ADMIN0000000000000000001",
        username="sales_a",
        password_hash=PasswordService().hash("zaq1XSW@"),
        display_name="业务员A",
        status="ACTIVE",
        roles=("SALESPERSON",),
        permissions=(
            "dashboard:read",
            "order:read",
            "attribution:read",
            "product:read",
            "product:write",
        ),
        data_scope="SELF",
    )
    identities.save_admin_user(admin)
    attribution = InMemoryAttributionRepository()
    salesperson, code = _seed_attribution(attribution, admin_user_id=admin.id)
    catalog = InMemoryCatalogRepository()
    manifest = build_seed_manifest()
    for product in manifest.products:
        catalog.save_product(product)
    for version in manifest.versions:
        catalog.save_version(version)
    enrollment = InMemoryEnrollmentRepository()
    app = create_app(
        settings=Settings(app_env="test"),
        identity_repository=identities,
        catalog_repository=catalog,
        agent_repository=InMemoryAgentRepository(),
        enrollment_repository=enrollment,
        attribution_repository=attribution,
    )

    with TestClient(app) as client:
        h5_login = client.post(
            "/api/v1/h5/auth/login",
            json={
                "mobile": "18800000001",
                "code": "147258",
                "referral_code": code.code,
            },
        )
        assert h5_login.status_code == 200
        h5_user_id = h5_login.json()["data"]["user"]["id"]
        assert h5_login.json()["data"]["attribution"]["attributed"] is True
        owned_order = _order("01ORDER0000000000000000001", h5_user_id)
        other_order = _order("01ORDER0000000000000000002", "01OTHERUSER0000000000000001")
        enrollment.save_order(owned_order)
        enrollment.save_order(other_order)
        attribution.save_order_attribution(
            OrderAttribution(
                id="01ATTR00000000000000000001",
                order_id=owned_order.id,
                h5_user_id=h5_user_id,
                salesperson_id=salesperson.id,
                promotion_code_id=code.id,
                source_code=code.code,
                amount_cents=owned_order.amount_cents,
                attributed_at=NOW,
            )
        )

        admin_login = client.post(
            "/api/v1/admin/auth/login",
            json={"username": "sales_a", "password": "zaq1XSW@"},
        )
        headers = {
            "Authorization": (f"Bearer {admin_login.json()['data']['tokens']['access_token']}")
        }
        orders = client.get("/api/v1/admin/orders", headers=headers)
        overview = client.get(
            "/api/v1/admin/attribution/overview",
            headers=headers,
        )
        products = client.get("/api/v1/admin/products", headers=headers)
        product_id = products.json()["data"]["items"][0]["product_id"]
        disabled = client.put(
            f"/api/v1/admin/products/{product_id}/status",
            headers=headers,
            json={"status": "INACTIVE"},
        )

    assert orders.status_code == 200
    assert orders.json()["data"]["total"] == 1
    visible_order = orders.json()["data"]["items"][0]
    assert visible_order["order_id"] == owned_order.id
    assert visible_order["applicant"]["id_no"] == "510104********1234"
    assert overview.json()["data"]["salesperson_count"] == 1
    assert overview.json()["data"]["order_count"] == 1
    assert disabled.status_code == 200
    assert disabled.json()["data"]["status"] == "INACTIVE"
