"""
Eclectic (org individuell turnering, ADR-067-tillegget "Del C", migrasjon
072) -- "drømmerunde" satt sammen av beste resultat per hull på tvers av
turneringens runder. Samme kall-direkte-mønster som
test_flag_plant_individual_tournament.py.
"""

import pytest
from fastapi import HTTPException

from app.auth import CurrentUser
from app.routers.individual_tournaments import (
    HoleUpdate,
    TournamentRoundCreate,
    create_round,
    individual_leaderboard,
    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_eclectic_tournament(scoring_method: str = "eclectic_gross"):
    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=4, stroke_index=n)
    tee_id = await create_tee(org_id, course_id)

    import app.db as app_db
    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, scoring_method,
        )

    round1_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=1)
    round2_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=2)
    player_id = await create_player(org_id, user_id=user_id)
    tp_id = await create_tournament_participant(org_id, tournament_id, player_id)
    # course_handicap=0 -- gjør netto/Stableford-tallene enkle å regne for hånd.
    rp1_id = await create_tournament_round_participant(org_id, round1_id, tp_id, tee_id, course_handicap=0)
    rp2_id = await create_tournament_round_participant(org_id, round2_id, tp_id, tee_id, course_handicap=0)
    return org_id, user_id, tournament_id, round1_id, round2_id, rp1_id, rp2_id, tp_id


async def _play_hole(tournament_id, round_id, rp_id, hole_number, score, org_id, user):
    await update_hole(
        tournament_id, round_id, rp_id, hole_number,
        HoleUpdate(gross_strokes=score),
        organization_id=org_id, user=user,
    )


async def test_eclectic_gross_picks_best_per_hole_across_rounds(pool):
    org_id, user_id, tournament_id, round1_id, round2_id, rp1_id, rp2_id, tp_id = (
        await _setup_eclectic_tournament("eclectic_gross")
    )
    user = CurrentUser(user_id=user_id)
    # Hull 1: runde 1 -> 5, runde 2 -> 6 (runde 1 vinner).
    # Hull 2: runde 1 -> 6, runde 2 -> 4 (runde 2 vinner).
    await _play_hole(tournament_id, round1_id, rp1_id, 1, 5, org_id, user)
    await _play_hole(tournament_id, round1_id, rp1_id, 2, 6, org_id, user)
    await _play_hole(tournament_id, round2_id, rp2_id, 1, 6, org_id, user)
    await _play_hole(tournament_id, round2_id, rp2_id, 2, 4, org_id, user)

    entries = await individual_leaderboard(tournament_id, organization_id=org_id)
    entry = next(e for e in entries if e.tournament_participant_id == tp_id)
    assert entry.eclectic_total == 5 + 4
    holes_by_number = {h.hole_number: h for h in entry.eclectic_holes}
    assert holes_by_number[1].value == 5
    assert holes_by_number[1].round_number == 1
    assert holes_by_number[2].value == 4
    assert holes_by_number[2].round_number == 2


async def test_eclectic_net_subtracts_strokes_received(pool):
    org_id, user_id, tournament_id, round1_id, round2_id, rp1_id, rp2_id, tp_id = (
        await _setup_eclectic_tournament("eclectic_net")
    )
    user = CurrentUser(user_id=user_id)
    await _play_hole(tournament_id, round1_id, rp1_id, 1, 5, org_id, user)

    entries = await individual_leaderboard(tournament_id, organization_id=org_id)
    entry = next(e for e in entries if e.tournament_participant_id == tp_id)
    # course_handicap=0 -- ingen mottatte slag, netto == brutto.
    assert entry.eclectic_total == 5


async def test_eclectic_stableford_picks_highest_points(pool):
    org_id, user_id, tournament_id, round1_id, round2_id, rp1_id, rp2_id, tp_id = (
        await _setup_eclectic_tournament("eclectic_stableford")
    )
    user = CurrentUser(user_id=user_id)
    # Par 4, HCP 0: gross 4 -> netto par -> 2 poeng. gross 3 -> netto birdie -> 3 poeng.
    await _play_hole(tournament_id, round1_id, rp1_id, 1, 4, org_id, user)
    await _play_hole(tournament_id, round2_id, rp2_id, 1, 3, org_id, user)

    entries = await individual_leaderboard(tournament_id, organization_id=org_id)
    entry = next(e for e in entries if e.tournament_participant_id == tp_id)
    assert entry.eclectic_total == 3
    assert entry.eclectic_holes[0].round_number == 2


async def test_eclectic_rejects_round_on_different_course(pool):
    org_id, user_id, tournament_id, round1_id, round2_id, rp1_id, rp2_id, tp_id = (
        await _setup_eclectic_tournament("eclectic_gross")
    )
    other_course_id = await create_course(org_id)
    for n in range(1, 19):
        await create_org_hole(org_id, other_course_id, hole_number=n, par=4, stroke_index=n)

    with pytest.raises(HTTPException) as exc_info:
        await create_round(
            tournament_id,
            TournamentRoundCreate(sequence=3, course_id=other_course_id),
            organization_id=org_id,
        )
    assert exc_info.value.status_code == 400
    assert exc_info.value.detail["code"] == "VALIDATION_FAILED"


async def test_non_eclectic_tournament_allows_different_courses(pool):
    org_id, user_id, tournament_id, round1_id, round2_id, rp1_id, rp2_id, tp_id = (
        await _setup_eclectic_tournament("stroke_gross")
    )
    other_course_id = await create_course(org_id)
    for n in range(1, 19):
        await create_org_hole(org_id, other_course_id, hole_number=n, par=4, stroke_index=n)

    result = await create_round(
        tournament_id,
        TournamentRoundCreate(sequence=3, course_id=other_course_id),
        organization_id=org_id,
    )
    assert result.course_id == other_course_id
