"""
Flaggturnering: GPS-flaggplanting + runde 2+ (migrasjon 069, 2026-08-14).
Kaller de faktiske router-funksjonene i rounds.py direkte, samme mønster
som test_concurrency_version_check.py -- ikke en gjenimplementering.

Kun frittstående runder (rounds.py) dekkes her -- individual_tournaments.py
sin org-speilende variant mangler conftest-hjelpere for tournament_round-
familien og er i stedet manuelt browserverifisert (se CHANGELOG.md).
"""

import pytest
from fastapi import HTTPException

from app import db as app_db
from app.auth import CurrentUser
from app.routers.rounds import (
    HoleUpdate,
    FlagPlantIn,
    FlagOverflowHoleIn,
    get_flag_map,
    get_flag_plant,
    list_flag_overflow_holes,
    plant_flag,
    unplant_flag,
    update_flag_overflow_hole,
    update_hole,
)

from tests.conftest import create_hole, create_participant, create_round, create_user


async def _setup_flag_round(holes_planned: int = 18, start_hole: int = 1):
    async with app_db.plain_connection() as conn:
        owner_id = await create_user()
        round_id = await create_round(conn, owner_id)
        await conn.execute(
            "UPDATE round SET play_format = 'flag', holes_planned = $2, start_hole = $3 WHERE id = $1",
            round_id, holes_planned, start_hole,
        )
        participant_id = await create_participant(
            conn, round_id, user_id=owner_id, is_owner=True, course_handicap_snapshot=10,
        )
        for n in range(1, 19):
            await create_hole(conn, participant_id, hole_number=n, par=4, stroke_index=n)
    return owner_id, round_id, participant_id


async def _play_hole(round_id: str, participant_id: str, hole_number: int, score: int, user: CurrentUser):
    await update_hole(round_id, participant_id, hole_number, HoleUpdate(score=score, played=True), user=user)


async def test_plant_flag_succeeds_on_first_unplayed_hole(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    await _play_hole(round_id, participant_id, 1, 5, user)
    await _play_hole(round_id, participant_id, 2, 4, user)

    result = await plant_flag(
        round_id, participant_id,
        FlagPlantIn(lat=59.9, lng=10.7, hole_number=3, lap=1, on_green=False),
        user=user,
    )
    assert result.lap == 1
    assert result.hole_number == 3
    assert result.on_green is False
    assert result.distance_to_pin_cm is None


async def test_plant_flag_rejects_mismatched_hole(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    await _play_hole(round_id, participant_id, 1, 5, user)
    # Faktisk posisjon er hull 2 (kun hull 1 spilt) -- forsøker å plante på hull 5.
    with pytest.raises(HTTPException) as exc_info:
        await plant_flag(
            round_id, participant_id,
            FlagPlantIn(lat=59.9, lng=10.7, hole_number=5, lap=1, on_green=False),
            user=user,
        )
    assert exc_info.value.status_code == 400
    assert exc_info.value.detail["code"] == "VALIDATION_FAILED"


async def test_plant_flag_on_green_requires_distance(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    with pytest.raises(HTTPException) as exc_info:
        await plant_flag(
            round_id, participant_id,
            FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=True),
            user=user,
        )
    assert exc_info.value.status_code == 400
    assert exc_info.value.detail["code"] == "VALIDATION_FAILED"


async def test_plant_flag_on_green_with_distance_succeeds(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    result = await plant_flag(
        round_id, participant_id,
        FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=True, distance_to_pin_cm=340),
        user=user,
    )
    assert result.on_green is True
    assert result.distance_to_pin_cm == 340


async def test_replanting_overwrites_not_duplicates(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    first = await plant_flag(
        round_id, participant_id,
        FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False),
        user=user,
    )
    await _play_hole(round_id, participant_id, 1, 5, user)
    second = await plant_flag(
        round_id, participant_id,
        FlagPlantIn(lat=60.0, lng=10.8, hole_number=2, lap=1, on_green=False),
        user=user,
    )
    assert second.id != first.id
    current = await get_flag_plant(round_id, participant_id, user=user)
    assert current.hole_number == 2


async def test_unplant_removes_flag(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    await plant_flag(
        round_id, participant_id,
        FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False),
        user=user,
    )
    await unplant_flag(round_id, participant_id, user=user)
    assert await get_flag_plant(round_id, participant_id, user=user) is None


async def test_get_flag_plant_none_when_never_planted(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    assert await get_flag_plant(round_id, participant_id, user=user) is None


async def test_overflow_hole_rejected_before_lap_one_complete(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    # Kun 5 av 18 hull spilt i lap 1 -- lap 2 skal avvises.
    for n in range(1, 6):
        await _play_hole(round_id, participant_id, n, 4, user)
    with pytest.raises(HTTPException) as exc_info:
        await update_flag_overflow_hole(
            round_id, participant_id, 2, 1, FlagOverflowHoleIn(score=4), user=user,
        )
    assert exc_info.value.status_code == 400
    assert exc_info.value.detail["code"] == "VALIDATION_FAILED"


async def test_full_lap_two_flow(pool):
    owner_id, round_id, participant_id = await _setup_flag_round()
    user = CurrentUser(user_id=owner_id)
    for n in range(1, 19):
        await _play_hole(round_id, participant_id, n, 4, user)

    # Forsøk på å plante i lap 1 avvises nå -- spilleren har allerede
    # fullført alle 18 hull i lap 1, faktisk posisjon er lap 2, hull 1.
    with pytest.raises(HTTPException) as exc_info:
        await plant_flag(
            round_id, participant_id,
            FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False),
            user=user,
        )
    assert exc_info.value.status_code == 400

    overflow_hole = await update_flag_overflow_hole(
        round_id, participant_id, 2, 1, FlagOverflowHoleIn(score=5), user=user,
    )
    assert overflow_hole.lap == 2
    assert overflow_hole.hole_number == 1
    assert overflow_hole.score == 5

    holes = await list_flag_overflow_holes(round_id, participant_id, user=user)
    assert len(holes) == 1
    assert holes[0].hole_number == 1

    # Nå kan flagget faktisk plantes riktig i lap 2, hull 2.
    lap2_plant = await plant_flag(
        round_id, participant_id,
        FlagPlantIn(lat=59.9, lng=10.7, hole_number=2, lap=2, on_green=False),
        user=user,
    )
    assert lap2_plant.lap == 2
    assert lap2_plant.hole_number == 2


async def test_flag_plant_respects_non_default_start_hole(pool):
    owner_id, round_id, participant_id = await _setup_flag_round(start_hole=10)
    user = CurrentUser(user_id=owner_id)
    # Spillerekkefølgen er 10,11,...,18,1,...,9 -- ingen hull spilt ennå,
    # så flagget skal kun kunne plantes på hull 10 (ikke fysisk hull 1).
    with pytest.raises(HTTPException) as exc_info:
        await plant_flag(
            round_id, participant_id,
            FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False),
            user=user,
        )
    assert exc_info.value.status_code == 400
    result = await plant_flag(
        round_id, participant_id,
        FlagPlantIn(lat=59.9, lng=10.7, hole_number=10, lap=1, on_green=False),
        user=user,
    )
    assert result.hole_number == 10


async def test_flag_map_shows_only_own_flag_when_switch_off(pool):
    owner_id, round_id, owner_participant_id = await _setup_flag_round()
    other_user_id = await create_user()
    async with app_db.plain_connection() as conn:
        other_participant_id = await create_participant(conn, round_id, user_id=other_user_id, is_owner=False)
    owner = CurrentUser(user_id=owner_id)
    other = CurrentUser(user_id=other_user_id)

    await plant_flag(
        round_id, owner_participant_id,
        FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False), user=owner,
    )
    await plant_flag(
        round_id, other_participant_id,
        FlagPlantIn(lat=60.0, lng=10.8, hole_number=1, lap=1, on_green=False), user=other,
    )

    result = await get_flag_map(round_id, user=owner)
    assert result.visible_to_all is False
    assert [f.participant_id for f in result.flags] == [owner_participant_id]


async def test_flag_map_shows_all_flags_when_switch_on(pool):
    owner_id, round_id, owner_participant_id = await _setup_flag_round()
    other_user_id = await create_user()
    async with app_db.plain_connection() as conn:
        other_participant_id = await create_participant(conn, round_id, user_id=other_user_id, is_owner=False)
        await conn.execute("UPDATE round SET flag_map_visible = true WHERE id = $1", round_id)
    owner = CurrentUser(user_id=owner_id)
    other = CurrentUser(user_id=other_user_id)

    await plant_flag(
        round_id, owner_participant_id,
        FlagPlantIn(lat=59.9, lng=10.7, hole_number=1, lap=1, on_green=False), user=owner,
    )
    await plant_flag(
        round_id, other_participant_id,
        FlagPlantIn(lat=60.0, lng=10.8, hole_number=1, lap=1, on_green=False), user=other,
    )

    result = await get_flag_map(round_id, user=other)
    assert result.visible_to_all is True
    assert {f.participant_id for f in result.flags} == {owner_participant_id, other_participant_id}
