"""Operator-surface contract for one-use customer invitations."""

from __future__ import annotations

import json
from pathlib import Path

import pytest
from pydantic import JsonValue, TypeAdapter

from gateway.platforms.dualcoach_admin import main
from gateway.platforms.dualcoach_customer_invite import CustomerInviteError
from gateway.platforms.telegram_customer_bootstrap import (
    BootstrapState,
    RoomBootstrapStore,
    room_bootstrap_state_dir,
)

_OBJECT = TypeAdapter(dict[str, JsonValue])


def _draft(path: Path) -> None:
    payload = {
        "customer_key": "new_customer_001",
        "display_name": "New Customer",
        "starts_on": "2026-09-01",
        "daily_time": "08:00",
        "weekly_weekday": 0,
        "monthly_day": 1,
        "calories_kcal": 2200,
        "protein_g": 140,
        "meals": ["breakfast", "lunch", "dinner"],
        "customer_user_id": "8527916639",
    }
    _ = path.write_text(json.dumps(payload), encoding="utf-8")
    path.chmod(0o600)


def _profile(path: Path) -> None:
    path.mkdir(mode=0o700)
    (path / "data").mkdir(mode=0o700)
    config = path / "config.yaml"
    _ = config.write_text(
        "".join((
            "platforms:\n",
            "  telegram:\n",
            "    extra:\n",
            "      production_preflight:\n",
            "        expected_bot_username: nutricoach_kr_bot\n",
        )),
        encoding="utf-8",
    )
    config.chmod(0o600)
    customers = path / "customers"
    customers.mkdir(mode=0o700)
    registry = customers / "registry.json"
    _ = registry.write_text(
        json.dumps({
            "owner": {"user_id": "8693203710"},
            "customers": [],
            "admission_policy": {"max_enabled_customers": 5},
        }),
        encoding="utf-8",
    )
    registry.chmod(0o600)


def test_customer_invite_command_prepares_one_private_token(
    tmp_path: Path,
    capsys: pytest.CaptureFixture[str],
) -> None:
    # Given
    profile = tmp_path / "profile"
    _profile(profile)
    draft = tmp_path / "draft.json"
    _draft(draft)

    # When
    exit_code = main((
        "customer",
        "invite",
        "--profile-root",
        str(profile),
        "--draft",
        str(draft),
        "--json",
    ))

    # Then
    assert exit_code == 0
    output = capsys.readouterr().out
    payload = _OBJECT.validate_json(output)
    customer_link = payload["customer_link"]
    assert isinstance(customer_link, str)
    assert customer_link.startswith("https://t.me/nutricoach_kr_bot?start=rc1_")
    sessions = RoomBootstrapStore(room_bootstrap_state_dir(profile)).list_sessions()
    assert len(sessions) == 1
    assert sessions[0].state is BootstrapState.PREPARED


def test_first_claim_invite_requires_no_customer_draft(
    tmp_path: Path,
    capsys: pytest.CaptureFixture[str],
) -> None:
    # Given: only the live operator profile exists.
    profile = tmp_path / "profile"
    _profile(profile)

    # When: the operator issues one first-claim invite without customer inputs.
    exit_code = main((
        "customer",
        "invite",
        "--profile-root",
        str(profile),
        "--first-claim",
        "--json",
    ))

    # Then: one unbound, single-use intake session is prepared.
    assert exit_code == 0
    payload = _OBJECT.validate_json(capsys.readouterr().out)
    assert str(payload["customer_link"]).startswith(
        "https://t.me/nutricoach_kr_bot?start=rc1_"
    )
    sessions = RoomBootstrapStore(room_bootstrap_state_dir(profile)).list_sessions()
    assert len(sessions) == 1
    assert sessions[0].state is BootstrapState.PREPARED
    assert sessions[0].customer_draft.customer_user_id is None
    assert sessions[0].first_claim is True


def test_customer_invite_rejects_symlinked_data_root(
    tmp_path: Path,
) -> None:
    # Given
    profile = tmp_path / "profile"
    _profile(profile)
    external = tmp_path / "external-data"
    external.mkdir(mode=0o700)
    (profile / "data").rmdir()
    (profile / "data").symlink_to(external, target_is_directory=True)
    draft = tmp_path / "draft.json"
    _draft(draft)

    # When / Then
    with pytest.raises(CustomerInviteError, match="profile data"):
        _ = main((
            "customer",
            "invite",
            "--profile-root",
            str(profile),
            "--draft",
            str(draft),
            "--json",
        ))
    assert not (external / "onboarding/telegram-room-bootstrap-v1").exists()


@pytest.mark.parametrize("relative", ["config.yaml", "customers/registry.json"])
def test_customer_invite_rejects_symlinked_authority_source(
    tmp_path: Path,
    relative: str,
) -> None:
    # Given
    profile = tmp_path / "profile"
    _profile(profile)
    source = profile / relative
    external = tmp_path / source.name
    _ = source.replace(external)
    source.symlink_to(external)
    draft = tmp_path / "draft.json"
    _draft(draft)

    # When / Then
    with pytest.raises(CustomerInviteError, match="unsafe"):
        _ = main((
            "customer",
            "invite",
            "--profile-root",
            str(profile),
            "--draft",
            str(draft),
            "--json",
        ))
