"""
Automatiserer det som til nå (ADR-057) kun er verifisert manuelt i tre lag
i nettleser: den optimistiske versjonssjekken på round_hole. Kaller de
faktiske router-funksjonene i rounds.py direkte (samme SQL, samme
feilhåndtering som produksjon) -- IKKE en gjenimplementering av logikken.
"""

import pytest
from fastapi import HTTPException

from app import db as app_db
from app.auth import CurrentUser
from app.routers.rounds import (
    HoleUpdate,
    SideHoleUpdate,
    update_hole,
    update_side_hole,
)

from tests.conftest import create_hole, create_participant, create_round


async def _setup_round_with_hole(hole_number: int = 1):
    async with app_db.plain_connection() as conn:
        from tests.conftest import create_user

        owner_id = await create_user()
        round_id = await create_round(conn, owner_id)
        participant_id = await create_participant(conn, round_id, user_id=owner_id, is_owner=True)
        await create_hole(conn, participant_id, hole_number=hole_number, par=4, stroke_index=9)
    return owner_id, round_id, participant_id


async def test_update_succeeds_and_increments_version(pool):
    owner_id, round_id, participant_id = await _setup_round_with_hole()
    user = CurrentUser(user_id=owner_id)

    out = await update_hole(
        round_id, participant_id, 1,
        HoleUpdate(score=5, expected_version=1),
        user=user,
    )
    assert out.score == 5
    assert out.version == 2


async def test_stale_version_is_rejected_with_409(pool):
    owner_id, round_id, participant_id = await _setup_round_with_hole()
    user = CurrentUser(user_id=owner_id)

    # "Enhet 1" leser versjon 1, skriver -- lykkes, hullet er nå versjon 2.
    await update_hole(round_id, participant_id, 1, HoleUpdate(score=4, expected_version=1), user=user)

    # "Enhet 2" leste OGSÅ versjon 1 (før enhet 1 sin skriving nådde den),
    # og prøver nå å skrive basert på den utdaterte versjonen.
    with pytest.raises(HTTPException) as exc_info:
        await update_hole(round_id, participant_id, 1, HoleUpdate(score=6, expected_version=1), 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):
    owner_id, round_id, participant_id = await _setup_round_with_hole()
    user = CurrentUser(user_id=owner_id)

    await update_hole(round_id, participant_id, 1, HoleUpdate(score=4, expected_version=1), user=user)
    # Hullet er nå versjon 2 -- men vi sender ingen forventet versjon i det
    # hele tatt (klient som ikke sender feltet, f.eks. eldre app-versjon).
    out = await update_hole(round_id, participant_id, 1, HoleUpdate(score=7, expected_version=None), user=user)
    assert out.score == 7
    assert out.version == 3


async def test_nonexistent_hole_is_404_not_409(pool):
    owner_id, round_id, participant_id = await _setup_round_with_hole(hole_number=1)
    user = CurrentUser(user_id=owner_id)

    with pytest.raises(HTTPException) as exc_info:
        await update_hole(round_id, participant_id, 18, HoleUpdate(score=4, expected_version=1), user=user)
    assert exc_info.value.status_code == 404
    assert exc_info.value.detail["code"] == "NOT_FOUND"


# ---------------------------------------------------------------------------
# round_side (delt-ball-format) -- update_side_hole har sin EGEN 404-vs-409-
# logikk (egen eksistenssjekk lagt til i samme runde som versjonskolonnen),
# adskilt kode fra update_hole -- verifiseres derfor separat, ikke antatt
# dekket av testene over.
# ---------------------------------------------------------------------------

async def _setup_round_with_side_hole(hole_number: int = 1):
    async with app_db.plain_connection() as conn:
        from tests.conftest import create_user, new_id

        owner_id = await create_user()
        round_id = await create_round(conn, owner_id)
        side_id = new_id()
        await conn.execute(
            "INSERT INTO round_side (id, round_id, label) VALUES ($1, $2, 'Side A')",
            side_id, round_id,
        )
        participant_id = await create_participant(
            conn, round_id, user_id=owner_id, is_owner=True,
        )
        await conn.execute(
            "UPDATE round_participant SET round_side_id = $1 WHERE id = $2", side_id, participant_id
        )
        await conn.execute(
            """
            INSERT INTO round_hole (round_side_id, hole_number, par, stroke_index, version)
            VALUES ($1, $2, 4, 9, 1)
            """,
            side_id, hole_number,
        )
    return owner_id, round_id, side_id


async def test_side_hole_stale_version_is_409(pool):
    owner_id, round_id, side_id = await _setup_round_with_side_hole()
    user = CurrentUser(user_id=owner_id)

    await update_side_hole(round_id, side_id, 1, SideHoleUpdate(score=4, expected_version=1), user=user)

    with pytest.raises(HTTPException) as exc_info:
        await update_side_hole(round_id, side_id, 1, SideHoleUpdate(score=6, expected_version=1), user=user)
    assert exc_info.value.status_code == 409
    assert exc_info.value.detail["code"] == "STALE_VERSION"


async def test_side_hole_nonexistent_is_404_not_409(pool):
    owner_id, round_id, side_id = await _setup_round_with_side_hole(hole_number=1)
    user = CurrentUser(user_id=owner_id)

    with pytest.raises(HTTPException) as exc_info:
        await update_side_hole(round_id, side_id, 18, SideHoleUpdate(score=4, expected_version=1), user=user)
    assert exc_info.value.status_code == 404
    assert exc_info.value.detail["code"] == "NOT_FOUND"
