from __future__ import annotations

import inspect
from copy import deepcopy

import pytest

from checkin_cli import customer_admin


def _require_contract() -> None:
    if not hasattr(customer_admin, "apply_nutrition_onboarding_projection"):
        pytest.fail("nutrition onboarding projection contract missing")
    if not hasattr(customer_admin, "project_nutrition_document"):
        pytest.fail("nutrition onboarding projection contract missing")


def _registry() -> dict[str, object]:
    return {
        "schema_version": "1.0",
        "customers": [
            {
                "customer_key": "target",
                "display_name": "Target",
                "enabled": False,
                "owner_key": "owner",
                "consent": {"privacy-v1": "granted"},
                "routes": {"customer": "opaque-customer", "owner": "opaque-owner"},
                "schedule": {"timezone": "Asia/Seoul", "checkin": "09:00"},
                "nutrition_profile": {"status": "draft"},
                "plan": {"weeks": [{"week": 1, "calories": 2000}]},
            },
            {
                "customer_key": "other",
                "display_name": "Other",
                "enabled": True,
                "nutrition_profile": {"status": "existing"},
                "plan": {"weeks": [{"week": 1, "calories": 2200}]},
            },
        ],
    }


def _project(document: dict[str, object]) -> dict[str, object]:
    _require_contract()
    return customer_admin.project_nutrition_document(
        document,
        customer_key="target",
        nutrition_profile={"status": "approved", "bundle_digest": "a" * 64},
        plan={"weeks": [{"week": 1, "calories": 2100}]},
    )


def test_projection_contract_is_present() -> None:
    _require_contract()
    signature = inspect.signature(customer_admin.apply_nutrition_onboarding_projection)
    assert "artifact_bundle_digest" in signature.parameters
    assert "readiness_receipt_digest" in signature.parameters


def test_projection_changes_only_target_nutrition_fields() -> None:
    before = _registry()
    after = _project(deepcopy(before))
    before_customers = before["customers"]
    after_customers = after["customers"]
    assert isinstance(before_customers, list)
    assert isinstance(after_customers, list)

    original_target = before_customers[0]
    projected_target = after_customers[0]
    assert isinstance(original_target, dict)
    assert isinstance(projected_target, dict)
    for key in (
        "customer_key",
        "display_name",
        "enabled",
        "owner_key",
        "consent",
        "routes",
        "schedule",
    ):
        assert projected_target[key] == original_target[key]
    assert projected_target["profile"] != original_target["nutrition_profile"]
    assert "nutrition_profile" not in projected_target
    assert projected_target["plan"] != original_target["plan"]
    assert after_customers[1] == before_customers[1]


def test_projection_rejects_enabled_target() -> None:
    document = _registry()
    customers = document["customers"]
    assert isinstance(customers, list)
    target = customers[0]
    assert isinstance(target, dict)
    target["enabled"] = True

    _require_contract()
    with pytest.raises(ValueError, match="disabled"):
        customer_admin.project_nutrition_document(
            document,
            customer_key="target",
            nutrition_profile={"status": "approved"},
            plan={"weeks": []},
        )


def test_projection_rejects_unknown_target() -> None:
    _require_contract()
    with pytest.raises(ValueError, match="unknown customer"):
        customer_admin.project_nutrition_document(
            _registry(),
            customer_key="missing",
            nutrition_profile={"status": "approved"},
            plan={"weeks": []},
        )


def test_projection_does_not_mutate_input() -> None:
    document = _registry()
    original = deepcopy(document)
    _project(document)
    assert document == original


def test_activation_v2_receipt_pins_readiness_bundle_and_projection() -> None:
    _require_contract()
    receipt = customer_admin.build_nutrition_activation_receipt_v2(
        customer_key="target",
        readiness_receipt_digest="a" * 64,
        readiness_bundle_digest="b" * 64,
        customer_projection_digest="c" * 64,
        input_reconciliation_digest="d" * 64,
    )
    assert receipt["schema_version"] == "nutrition_activation_v2"
    assert receipt["customer_key"] == "target"
    assert receipt["readiness_receipt_digest"] == "a" * 64
    assert receipt["readiness_bundle_digest"] == "b" * 64
    assert receipt["customer_projection_digest"] == "c" * 64
    assert receipt["input_reconciliation_digest"] == "d" * 64
    assert len(receipt["digest"]) == 64


def test_legacy_manifest_is_bounded_to_exact_existing_customer() -> None:
    _require_contract()
    manifest = customer_admin.build_legacy_activation_authority(
        customer_key="legacy",
        activation_receipt_digest="a" * 64,
        registry_projection_digest="b" * 64,
        owner_digest="c" * 64,
    )
    assert customer_admin.validate_legacy_activation_authority(
        manifest,
        customer_key="legacy",
        activation_receipt_digest="a" * 64,
        registry_projection_digest="b" * 64,
        owner_digest="c" * 64,
    )
    assert not customer_admin.validate_legacy_activation_authority(
        manifest,
        customer_key="new-customer",
        activation_receipt_digest="a" * 64,
        registry_projection_digest="b" * 64,
        owner_digest="c" * 64,
    )
