"""
Full statistikkdybde + optimistisk versjonssjekk på tournament_round_hole
(migrasjon 075, ADR-071) -- speiler test_concurrency_version_check.py sitt
mønster for round_hole, men gjennom individual_tournaments.py sin egen
update_hole (self-only autorisasjon, upsert i stedet for ren UPDATE siden
raden ikke finnes før første score).
"""

import pytest
from fastapi import HTTPException

from app.auth import CurrentUser
from app.routers.individual_tournaments import (
    HoleUpdate,
    TournamentParticipantCreate,
    add_tournament_participant,
    update_hole,
)

from tests.conftest import (
    add_membership,
    create_org,
    create_org_hole,
    create_course,
    create_player,
    create_tee,
    create_tournament,
    create_tournament_participant,
    create_tournament_round,
    create_tournament_round_participant,
    create_user,
)


async def _setup_tournament(par=4):
    org_id = await create_org()
    user_id = await create_user()
    await add_membership(org_id, user_id, role="owner")
    tournament_id = await create_tournament(org_id)
    course_id = await create_course(org_id)
    for n in range(1, 19):
        await create_org_hole(
            org_id, course_id, hole_number=n,
            par=par if n == 1 else 4,
            stroke_index=n,
        )
    tee_id = await create_tee(org_id, course_id)
    tournament_round_id = await create_tournament_round(org_id, tournament_id, course_id)
    player_id = await create_player(org_id, user_id=user_id)
    tp_id = await create_tournament_participant(org_id, tournament_id, player_id)
    rp_id = await create_tournament_round_participant(org_id, tournament_round_id, tp_id, tee_id)
    return org_id, user_id, tournament_id, tournament_round_id, rp_id


async def test_update_succeeds_and_increments_version(pool):
    org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament()
    user = CurrentUser(user_id=user_id)

    out = await update_hole(
        tournament_id, round_id, rp_id, 1,
        HoleUpdate(gross_strokes=5, putts=2, expected_version=None),
        organization_id=org_id, user=user,
    )
    assert out.gross_strokes == 5
    assert out.putts == 2
    assert out.version == 1


async def test_stale_version_is_rejected_with_409(pool):
    org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament()
    user = CurrentUser(user_id=user_id)

    # Første innsending -- raden finnes ikke fra før, INSERT-grenen treffes
    # ubetinget uansett expected_version. Hullet er nå versjon 1.
    await update_hole(
        tournament_id, round_id, rp_id, 1,
        HoleUpdate(gross_strokes=4, expected_version=None),
        organization_id=org_id, user=user,
    )
    # "Enhet 1" leser versjon 1, skriver -- lykkes, hullet er nå versjon 2.
    await update_hole(
        tournament_id, round_id, rp_id, 1,
        HoleUpdate(gross_strokes=4, expected_version=1),
        organization_id=org_id, user=user,
    )

    # "Enhet 2" leste OGSÅ versjon 1 (før enhet 1 sin skriving nådde den).
    with pytest.raises(HTTPException) as exc_info:
        await update_hole(
            tournament_id, round_id, rp_id, 1,
            HoleUpdate(gross_strokes=6, expected_version=1),
            organization_id=org_id, user=user,
        )
    assert exc_info.value.status_code == 409
    assert exc_info.value.detail["code"] == "STALE_VERSION"


async def test_expected_version_none_bypasses_check(pool):
    org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament()
    user = CurrentUser(user_id=user_id)

    await update_hole(
        tournament_id, round_id, rp_id, 1,
        HoleUpdate(gross_strokes=4, expected_version=None),
        organization_id=org_id, user=user,
    )
    await update_hole(
        tournament_id, round_id, rp_id, 1,
        HoleUpdate(gross_strokes=4, expected_version=1),
        organization_id=org_id, user=user,
    )
    # Hullet er nå versjon 2 -- men klienten sender ingen forventet versjon.
    out = await update_hole(
        tournament_id, round_id, rp_id, 1,
        HoleUpdate(gross_strokes=7, expected_version=None),
        organization_id=org_id, user=user,
    )
    assert out.gross_strokes == 7
    assert out.version == 3


async def test_first_write_succeeds_regardless_of_expected_version(pool):
    """Raden finnes ikke før første score -- INSERT-grenen er ubetinget, så
    selv en helt feil expected_version må IKKE blokkere en fersk innsending
    (ulikt round_hole, der raden alltid finnes fra rundestart)."""
    org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament()
    user = CurrentUser(user_id=user_id)

    out = await update_hole(
        tournament_id, round_id, rp_id, 1,
        HoleUpdate(gross_strokes=5, expected_version=99),
        organization_id=org_id, user=user,
    )
    assert out.gross_strokes == 5
    assert out.version == 1


async def test_full_stat_fields_round_trip(pool):
    org_id, user_id, tournament_id, round_id, rp_id = await _setup_tournament(par=4)
    user = CurrentUser(user_id=user_id)

    out = await update_hole(
        tournament_id, round_id, rp_id, 1,
        HoleUpdate(
            gross_strokes=4,
            putts=1,
            club_off_tee="Driver",
            tee_shot_result="fairway",
            approach_result="hit",
            chip_count=0,
            bunker_shot_count=1,
            penalty_strokes=0,
            first_putt_distance_bucket="<3m",
            anyway_strokes=0,
            expected_version=None,
        ),
        organization_id=org_id, user=user,
    )
    assert out.putts == 1
    assert out.club_off_tee == "Driver"
    assert out.tee_shot_result == "fairway"
    assert out.approach_result == "hit"
    assert out.bunker_shot_count == 1
    assert out.first_putt_distance_bucket == "<3m"


async def test_stat_level_defaults_to_strokes_only_and_is_settable_on_create(pool):
    org_id = await create_org()
    user_id = await create_user()
    await add_membership(org_id, user_id, role="owner")
    tournament_id = await create_tournament(org_id)
    player_id = await create_player(org_id, user_id=user_id)

    default_out = await add_tournament_participant(
        tournament_id, TournamentParticipantCreate(player_id=player_id),
        organization_id=org_id,
    )
    assert default_out.stat_level == "strokes_only"

    player_id_2 = await create_player(org_id)
    full_out = await add_tournament_participant(
        tournament_id,
        TournamentParticipantCreate(player_id=player_id_2, stat_level="full"),
        organization_id=org_id,
    )
    assert full_out.stat_level == "full"
