"""
ADR-060: samme optimistiske versjonssjekk som round_hole (ADR-057) fikk,
nå for org-turneringenes match-scoring (hole_score/match_hole_result,
app/routers/scoring.py). Kaller de faktiske router-funksjonene direkte --
samme kodesti som produksjon, ikke en SQL-gjenimplementering.

Autorisasjon: testbrukeren er satt som org-EIER (organization_membership
role='owner'), som tilfredsstiller user_is_match_participant sin
is_org_admin-fallback (team_authz.py) uten å måtte bygge ut hele
player/team_roster/match_participant-kjeden for HVER test -- kun
test_hole_score_individual_ball_participant_path bygger den fulle kjeden,
siden DEN grenen i submit_hole_score krever en ekte match_participant-rad
å slå opp uavhengig av org-admin-status.
"""

import pytest
from fastapi import HTTPException

from app import db as app_db
from app.auth import CurrentUser
from app.routers.scoring import (
    HoleResultCreate,
    HoleScoreCreate,
    submit_hole_result,
    submit_hole_score,
)

from tests.conftest import (
    add_membership,
    create_course,
    create_match,
    create_match_participant,
    create_org,
    create_player,
    create_session,
    create_team,
    create_team_roster,
    create_tee,
    create_tournament,
    create_user,
)


async def _setup_match(scoring_mode: str = "stroke", format_: str = "foursome"):
    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)
    team_a = await create_team(org_id, tournament_id)
    team_b = await create_team(org_id, tournament_id)
    course_id = await create_course(org_id)
    session_id = await create_session(
        org_id, tournament_id, course_id, format=format_, scoring_mode=scoring_mode
    )
    match_id = await create_match(org_id, session_id, team_a, team_b)
    return org_id, user_id, match_id, team_a, team_b


async def test_hole_score_shared_ball_succeeds_and_increments_version(pool):
    org_id, user_id, match_id, _, _ = await _setup_match()
    user = CurrentUser(user_id=user_id)

    first = await submit_hole_score(
        match_id,
        HoleScoreCreate(team_side="a", hole_number=1, gross_strokes=5, expected_version=None),
        org_id,
        user=user,
    )
    assert first.version == 1
    assert first.gross_strokes == 5

    second = await submit_hole_score(
        match_id,
        HoleScoreCreate(team_side="a", hole_number=1, gross_strokes=4, expected_version=1),
        org_id,
        user=user,
    )
    assert second.version == 2
    assert second.gross_strokes == 4


async def test_hole_score_stale_version_is_409(pool):
    org_id, user_id, match_id, _, _ = await _setup_match()
    user = CurrentUser(user_id=user_id)

    await submit_hole_score(
        match_id,
        HoleScoreCreate(team_side="a", hole_number=1, gross_strokes=5, expected_version=None),
        org_id,
        user=user,
    )
    # "Enhet 2" hadde OGSÅ lest versjon 1 (før dette skjedde), og prøver nå
    # å skrive med en versjon som allerede er forbigått.
    with pytest.raises(HTTPException) as exc_info:
        await submit_hole_score(
            match_id,
            HoleScoreCreate(team_side="a", hole_number=1, gross_strokes=6, expected_version=99),
            org_id,
            user=user,
        )
    assert exc_info.value.status_code == 409
    assert exc_info.value.detail["code"] == "STALE_VERSION"

    # Og bekreft at den avviste skrivingen faktisk IKKE ble lagret.
    async with app_db.org_connection(org_id) as conn:
        row = await conn.fetchrow(
            "SELECT gross_strokes, version FROM hole_score WHERE match_id = $1 AND hole_number = 1", match_id
        )
    assert row["gross_strokes"] == 5
    assert row["version"] == 1


async def test_hole_score_expected_version_none_bypasses_check(pool):
    org_id, user_id, match_id, _, _ = await _setup_match()
    user = CurrentUser(user_id=user_id)

    await submit_hole_score(
        match_id,
        HoleScoreCreate(team_side="a", hole_number=1, gross_strokes=5, expected_version=None),
        org_id,
        user=user,
    )
    out = await submit_hole_score(
        match_id,
        HoleScoreCreate(team_side="a", hole_number=1, gross_strokes=7, expected_version=None),
        org_id,
        user=user,
    )
    assert out.gross_strokes == 7
    assert out.version == 2


async def test_hole_score_individual_ball_participant_path(pool):
    """Den ANDRE ON CONFLICT-grenen i submit_hole_score (match_participant_id
    satt) -- egen kode, egen WHERE-versjonssjekk, verdt å dekke separat fra
    delt-ball-testene over. Krever en ekte match_participant-rad (kylling-
    og-egg: user_is_match_participant sin participant-sjekk er uavhengig av
    org-admin-fallbacken for AKKURAT denne oppslags-grenen i
    submit_hole_score, se linje ~534 i scoring.py)."""
    org_id, user_id, match_id, team_a, _ = await _setup_match(format_="singles")
    user = CurrentUser(user_id=user_id)

    course_id = await create_course(org_id)
    tee_id = await create_tee(org_id, course_id)
    player_id = await create_player(org_id, user_id=user_id)
    roster_id = await create_team_roster(org_id, team_a, player_id)
    participant_id = await create_match_participant(org_id, match_id, "a", roster_id, tee_id)

    first = await submit_hole_score(
        match_id,
        HoleScoreCreate(
            team_side="a", match_participant_id=participant_id, hole_number=1,
            gross_strokes=4, expected_version=None,
        ),
        org_id,
        user=user,
    )
    assert first.version == 1

    with pytest.raises(HTTPException) as exc_info:
        await submit_hole_score(
            match_id,
            HoleScoreCreate(
                team_side="a", match_participant_id=participant_id, hole_number=1,
                gross_strokes=9, expected_version=99,
            ),
            org_id,
            user=user,
        )
    assert exc_info.value.status_code == 409
    assert exc_info.value.detail["code"] == "STALE_VERSION"


async def test_hole_result_succeeds_and_increments_version(pool):
    org_id, user_id, match_id, _, _ = await _setup_match(scoring_mode="hole_result")
    user = CurrentUser(user_id=user_id)

    first = await submit_hole_result(
        match_id, HoleResultCreate(hole_number=1, winning_side="a", expected_version=None), org_id, user=user
    )
    assert first.version == 1
    assert first.winning_side == "a"

    second = await submit_hole_result(
        match_id, HoleResultCreate(hole_number=1, winning_side="b", expected_version=1), org_id, user=user
    )
    assert second.version == 2
    assert second.winning_side == "b"


async def test_hole_result_stale_version_is_409(pool):
    org_id, user_id, match_id, _, _ = await _setup_match(scoring_mode="hole_result")
    user = CurrentUser(user_id=user_id)

    await submit_hole_result(
        match_id, HoleResultCreate(hole_number=1, winning_side="a", expected_version=None), org_id, user=user
    )
    with pytest.raises(HTTPException) as exc_info:
        await submit_hole_result(
            match_id, HoleResultCreate(hole_number=1, winning_side="b", expected_version=99), org_id, user=user
        )
    assert exc_info.value.status_code == 409
    assert exc_info.value.detail["code"] == "STALE_VERSION"
