"""
Tiebreak ved likt resultat i individuelle turneringer (migrasjon 085,
2026-08-18). Bruker: "Ved likt resultat ... Skal laveste hcp plasseres
foran, beste siste 18/9/6/3/siste hull plasseres foran, eller deles
plasseringene. Her kan svaret være forskjellig for vinner og resten av
feltet." Metoden er en fri organisator-innstilling, ikke fastlåst --
to UAVHENGIGE felt (vinner/felt), og påvirker ALDRI Cut-grensen (kun
sluttresultatets plasseringsvisning).
"""

from app.routers.individual_tournaments import (
    HoleUpdate as TournamentHoleUpdate,
    apply_cut,
    individual_leaderboard,
    update_hole as tournament_update_hole,
)
from app.routers.tournaments import TournamentUpdate, update_tournament
from app.auth import CurrentUser

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,
)

import app.db as app_db


async def _score_holes(tournament_id, round_id, rp_id, org_id, user_id, scores: list[int]) -> None:
    user = CurrentUser(user_id=user_id)
    for n, gross in enumerate(scores, start=1):
        await tournament_update_hole(
            tournament_id, round_id, rp_id, n,
            TournamentHoleUpdate(gross_strokes=gross, expected_version=None),
            organization_id=org_id, user=user,
        )


async def _setup_single_round(org_id, owner_id, method="stroke_gross"):
    tournament_id = await create_tournament(org_id, name="Tiebreak-turnering")
    course_id = await create_course(org_id, name="Tiebreak Links")
    for n in range(1, 19):
        await create_org_hole(org_id, course_id, hole_number=n, par=4, stroke_index=n)
    tee_id = await create_tee(org_id, course_id)
    async with app_db.org_connection(org_id) as conn:
        await conn.execute(
            "UPDATE tournament SET format_type = 'individual', scoring_method = $2 WHERE id = $1",
            tournament_id, method,
        )
    round_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=1)
    return tournament_id, course_id, tee_id, round_id


async def _set_tiebreak(org_id, tournament_id, winner: str, field: str):
    await update_tournament(
        tournament_id,
        TournamentUpdate(tiebreak_winner_method=winner, tiebreak_field_method=field),
        organization_id=org_id,
    )


async def test_countback_resolves_winner_tie_by_better_back_nine(pool):
    org_id = await create_org()
    owner_id = await create_user()
    await add_membership(org_id, owner_id, role="owner")
    tournament_id, course_id, tee_id, round_id = await _setup_single_round(org_id, owner_id)
    await _set_tiebreak(org_id, tournament_id, winner="countback", field="none")

    p1 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P1"))
    p2 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P2"))
    p3 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P3"))

    rp1 = await create_tournament_round_participant(org_id, round_id, p1, tee_id)
    rp2 = await create_tournament_round_participant(org_id, round_id, p2, tee_id)
    rp3 = await create_tournament_round_participant(org_id, round_id, p3, tee_id)

    # P1: front9 alle par (36), back9 to birdier (34) -> total 70, back9=34.
    p1_scores = [4] * 9 + [3, 3] + [4] * 7
    # P2: front9 to birdier (34), back9 alle par (36) -> total 70, back9=36 (dårligere enn P1 sin back9).
    p2_scores = [3, 3] + [4] * 7 + [4] * 9
    # P3: klart bak, ingen uavgjort.
    p3_scores = [5] * 18

    await _score_holes(tournament_id, round_id, rp1, org_id, owner_id, p1_scores)
    await _score_holes(tournament_id, round_id, rp2, org_id, owner_id, p2_scores)
    await _score_holes(tournament_id, round_id, rp3, org_id, owner_id, p3_scores)

    entries = await individual_leaderboard(tournament_id, organization_id=org_id)
    by_id = {e.tournament_participant_id: e for e in entries}

    assert by_id[p1].position == "1"  # bedre back9 -> sole leder, IKKE "T1"
    assert by_id[p1].is_leader is True
    assert by_id[p2].position == "2"
    assert by_id[p2].is_leader is False
    assert by_id[p3].position == "3"


async def test_lowest_hcp_resolves_field_tie_but_not_winner(pool):
    org_id = await create_org()
    owner_id = await create_user()
    await add_membership(org_id, owner_id, role="owner")
    tournament_id, course_id, tee_id, round_id = await _setup_single_round(org_id, owner_id)
    # Vinner-tiebreak IKKE satt (none) -- kun felt-tiebreak skal virke.
    await _set_tiebreak(org_id, tournament_id, winner="none", field="lowest_hcp")

    leader = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="Leader"))
    p2 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P2"))
    p3 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P3"))

    async with app_db.org_connection(org_id) as conn:
        await conn.execute("UPDATE tournament_participant SET handicap_index_snapshot = 8.0 WHERE id = $1", p2)
        await conn.execute("UPDATE tournament_participant SET handicap_index_snapshot = 20.0 WHERE id = $1", p3)

    rp_leader = await create_tournament_round_participant(org_id, round_id, leader, tee_id)
    rp2 = await create_tournament_round_participant(org_id, round_id, p2, tee_id)
    rp3 = await create_tournament_round_participant(org_id, round_id, p3, tee_id)

    await _score_holes(tournament_id, round_id, rp_leader, org_id, owner_id, [3] * 18)  # klar leder, -18
    await _score_holes(tournament_id, round_id, rp2, org_id, owner_id, [4] * 18)  # uavgjort med p3, E
    await _score_holes(tournament_id, round_id, rp3, org_id, owner_id, [4] * 18)  # uavgjort med p2, E

    entries = await individual_leaderboard(tournament_id, organization_id=org_id)
    by_id = {e.tournament_participant_id: e for e in entries}

    assert by_id[leader].position == "1"
    assert by_id[leader].is_leader is True
    assert by_id[p2].position == "2"  # lavere HCP (8.0 < 20.0) -> foran
    assert by_id[p3].position == "3"


async def test_tiebreak_method_none_keeps_shared_position(pool):
    """Standard/uendret oppførsel -- ingen tiebreak konfigurert i det hele
    tatt (default 'none' for begge felt, ingen regresjon)."""
    org_id = await create_org()
    owner_id = await create_user()
    await add_membership(org_id, owner_id, role="owner")
    tournament_id, course_id, tee_id, round_id = await _setup_single_round(org_id, owner_id)

    p1 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P1"))
    p2 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P2"))
    rp1 = await create_tournament_round_participant(org_id, round_id, p1, tee_id)
    rp2 = await create_tournament_round_participant(org_id, round_id, p2, tee_id)

    await _score_holes(tournament_id, round_id, rp1, org_id, owner_id, [4] * 18)
    await _score_holes(tournament_id, round_id, rp2, org_id, owner_id, [4] * 18)

    entries = await individual_leaderboard(tournament_id, organization_id=org_id)
    by_id = {e.tournament_participant_id: e for e in entries}
    assert by_id[p1].position == "T1"
    assert by_id[p2].position == "T1"
    assert by_id[p1].is_leader is True
    assert by_id[p2].is_leader is True


async def test_playoff_method_keeps_shared_position_like_none(pool):
    """'playoff' (migrasjon 086) -- appen kan ikke selv avgjøre et
    omspill, så en tiebreak_winner_method='playoff'-turnering skal
    oppføre seg NØYAKTIG som 'none' i selve rangeringen (delt plassering,
    ingen automatisk oppløsning) -- forskjellen er ren informasjon
    (tiebreak_playoff_rule), ikke rangeringslogikk."""
    org_id = await create_org()
    owner_id = await create_user()
    await add_membership(org_id, owner_id, role="owner")
    tournament_id, course_id, tee_id, round_id = await _setup_single_round(org_id, owner_id)
    await update_tournament(
        tournament_id,
        TournamentUpdate(tiebreak_winner_method="playoff", tiebreak_playoff_rule="Sudden death fra hull 18."),
        organization_id=org_id,
    )

    p1 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P1"))
    p2 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P2"))
    rp1 = await create_tournament_round_participant(org_id, round_id, p1, tee_id)
    rp2 = await create_tournament_round_participant(org_id, round_id, p2, tee_id)

    await _score_holes(tournament_id, round_id, rp1, org_id, owner_id, [4] * 18)
    await _score_holes(tournament_id, round_id, rp2, org_id, owner_id, [4] * 18)

    entries = await individual_leaderboard(tournament_id, organization_id=org_id)
    by_id = {e.tournament_participant_id: e for e in entries}
    assert by_id[p1].position == "T1"
    assert by_id[p2].position == "T1"
    assert by_id[p1].is_leader is True
    assert by_id[p2].is_leader is True


async def test_tiebreak_never_affects_cut_boundary(pool):
    """Bruker bekreftet eksplisitt: tiebreak påvirker KUN sluttresultatet,
    ALDRI selve cut-grensen -- full delt plass på grensen uansett
    tiebreak-innstilling."""
    org_id = await create_org()
    owner_id = await create_user()
    await add_membership(org_id, owner_id, role="owner")
    tournament_id, course_id, tee_id, round1_id = await _setup_single_round(org_id, owner_id)
    round2_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=2)
    # Countback konfigurert -- skal likevel IKKE påvirke cutten.
    await _set_tiebreak(org_id, tournament_id, winner="countback", field="countback")
    await update_tournament(
        tournament_id, TournamentUpdate(cut_after_round=1, cut_size=1), organization_id=org_id,
    )

    p1 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P1"))
    p2 = await create_tournament_participant(org_id, tournament_id, await create_player(org_id, display_name="P2"))
    rp1 = await create_tournament_round_participant(org_id, round1_id, p1, tee_id)
    rp2 = await create_tournament_round_participant(org_id, round1_id, p2, tee_id)
    # Identisk totalt OG identisk back9 -- ekte fullt uavgjort, selv med countback slått på.
    await _score_holes(tournament_id, round1_id, rp1, org_id, owner_id, [4] * 18)
    await _score_holes(tournament_id, round1_id, rp2, org_id, owner_id, [4] * 18)

    result = await apply_cut(tournament_id, organization_id=org_id)
    assert result.cut_size == 1
    assert result.survivors == 2  # begge slipper gjennom -- delt 1.-plass, IKKE brutt av countback
    assert result.cut_count == 0
