from __future__ import annotations

import json
from pathlib import Path

from checkin_cli.wizard import WizardContext, WizardService, WizardStatus


def test_nutrition_daily_persists_full_nutrition_and_recovery_snapshot(tmp_path: Path) -> None:
    service = WizardService.for_standalone(tmp_path)
    context = WizardContext("client-1", "topic-1")
    started = service.start_nutrition(context, "2026-07-20")
    answers = (
        ("value", "70.2"),
        ("value", "2350"),
        ("value", "285 150 65"),
        ("value", "아침 오트밀, 점심 닭가슴살, 저녁 연어"),
        ("value", "2.5"),
        ("value", "7.5"),
        ("select", "4"),
        ("select", "normal"),
        ("select", "4"),
        ("value", "식욕 3/5, 스트레스 2/5"),
        ("value", "하체 70분, 보통 강도"),
        ("select", "skip"),
    )

    result = started
    for action, value in answers:
        result = service.answer(context, result.session_id, result.version, action, value)
        assert result.status is WizardStatus.ADVANCED
    saved = service.answer(context, result.session_id, result.version, "save")

    assert saved.status is WizardStatus.SAVED
    event = json.loads((tmp_path / "events.jsonl").read_text(encoding="utf-8"))
    assert event["event_type"] == "nutrition_checkin"
    assert event["check_in"] == {
        "body_weight_kg": 70.2,
        "calories_kcal": 2350,
        "protein_g": 150,
        "carbohydrate_g": 285,
        "fat_g": 65,
        "sleep_hours": 7.5,
        "sleep_quality_1to5": 4,
        "readiness_1to5": 4,
        "training_summary": "하체 70분, 보통 강도",
        "digestion_summary": "normal",
        "meal_summary": "아침 오트밀, 점심 닭가슴살, 저녁 연어",
        "water_liters": 2.5,
        "appetite_stress_summary": "식욕 3/5, 스트레스 2/5",
    }


def test_completed_nutrition_day_reopens_without_duplicate_event(tmp_path: Path) -> None:
    service = WizardService.for_standalone(tmp_path)
    context = WizardContext("client-1", "topic-1")
    started = service.start_nutrition(context, "2026-07-20")
    answers = (
        ("value", "70"), ("value", "2300"), ("value", "280 150 65"),
        ("value", "계획대로 3식"), ("value", "2.3"), ("value", "7"),
        ("select", "3"), ("select", "normal"), ("select", "3"),
        ("value", "식욕 3/5, 스트레스 3/5"), ("value", "휴식"), ("select", "skip"),
    )
    result = started
    for action, value in answers:
        result = service.answer(context, result.session_id, result.version, action, value)
    service.answer(context, result.session_id, result.version, "save")

    reopened = WizardService.for_standalone(tmp_path).start_nutrition(context, "2026-07-20")

    assert reopened.status is WizardStatus.SAVED
    assert reopened.session_id == started.session_id
    assert len((tmp_path / "events.jsonl").read_text(encoding="utf-8").splitlines()) == 1


def test_completed_nutrition_day_can_be_corrected_with_an_append_only_event(tmp_path: Path) -> None:
    service = WizardService.for_standalone(tmp_path)
    context = WizardContext("client-1", "topic-1")
    started = service.start_nutrition(context, "2026-07-20")
    answers = (
        ("value", "70"), ("value", "2300"), ("value", "280 150 65"),
        ("value", "계획대로 3식"), ("value", "2.3"), ("value", "7"),
        ("select", "3"), ("select", "normal"), ("select", "3"),
        ("value", "식욕 3/5, 스트레스 3/5"), ("value", "휴식"), ("select", "skip"),
    )
    result = started
    for action, value in answers:
        result = service.answer(context, result.session_id, result.version, action, value)
    service.answer(context, result.session_id, result.version, "save")

    correction = service.start_nutrition_correction(context, "2026-07-20")

    assert correction.status is WizardStatus.ADVANCED
    result = service.answer(
        context, correction.session_id, correction.version, "edit", "bodyweight"
    )
    result = service.answer(context, result.session_id, result.version, "value", "70.2")
    saved = service.answer(context, result.session_id, result.version, "save")
    events = [json.loads(line) for line in (tmp_path / "events.jsonl").read_text(encoding="utf-8").splitlines()]

    assert saved.status is WizardStatus.SAVED
    assert events[1]["event_type"] == "correction"
    assert events[1]["supersedes"] == events[0]["event_id"]
    assert events[1]["check_in"]["body_weight_kg"] == 70.2


def test_repeated_nutrition_corrections_accumulate_from_latest_snapshot(tmp_path: Path) -> None:
    service = WizardService.for_standalone(tmp_path)
    context = WizardContext("client-1", "topic-1")
    result = service.start_nutrition(context, "2026-07-20")
    for action, value in (
        ("value", "70"), ("value", "2300"), ("value", "280 150 65"),
        ("value", "Meal 1 밥 / Meal 2 닭가슴살"), ("value", "2.3"), ("value", "7"),
        ("select", "3"), ("select", "normal"), ("select", "3"),
        ("value", "식욕 3 스트레스 3"), ("value", "휴식"), ("select", "skip"),
    ):
        result = service.answer(context, result.session_id, result.version, action, value)
    service.answer(context, result.session_id, result.version, "save")

    first = service.start_nutrition_correction(context, "2026-07-20")
    first = service.answer(context, first.session_id, first.version, "edit", "bodyweight")
    first = service.answer(context, first.session_id, first.version, "value", "70.2")
    service.answer(context, first.session_id, first.version, "save")

    second = service.start_nutrition_correction(context, "2026-07-20")
    assert second.status is WizardStatus.ADVANCED
    second_session = service._storage.load(second.session_id)
    assert second_session is not None
    assert second_session.answers["bodyweight"] == "70.2"
    second = service.answer(context, second.session_id, second.version, "edit", "water")
    second = service.answer(context, second.session_id, second.version, "value", "3.0")
    service.answer(context, second.session_id, second.version, "save")

    events = [
        json.loads(line)
        for line in (tmp_path / "events.jsonl").read_text(encoding="utf-8").splitlines()
    ]
    assert [event.get("supersedes") for event in events] == [
        None,
        events[0]["event_id"],
        events[1]["event_id"],
    ]
    assert events[2]["check_in"]["body_weight_kg"] == 70.2
    assert events[2]["check_in"]["water_liters"] == 3.0
