"""
Spillerens per-hull-historikk (ADR-072). To lag med tester:

1. Rene enhetstester av summarize_hole_history() -- ingen db, bevis at
   GIR%/fairway%/gjennomsnitt regnes riktig og hopper over rader uten data.
2. Integrasjonstester mot ekte router-funksjoner (samme mønster som
   test_tournament_hole_stats.py/test_concurrency_version_check.py) --
   beviser selve bane-broen: samme fysiske (teeoff-)bane spilt både som
   frittstående runde OG i en org-turnering i en ANNEN organisasjon enn
   spilleren selv eier noe i, skal telles sammen. Custom-baner og
   gjestespillere skal BEVISST ekskluderes (bruker-bekreftet scope).
"""

import uuid
from datetime import date

from app.auth import CurrentUser
from app.hole_history import (
    HoleInstance,
    hole_history_for_user,
    resolve_personal_round_course_key,
    summarize_hole_history,
)
from app.routers.individual_tournaments import (
    HoleUpdate as TournamentHoleUpdate,
    update_hole as tournament_update_hole,
)
from app.routers.rounds import HoleUpdate as RoundHoleUpdate, get_hole_history, update_hole as round_update_hole
from app.routers.individual_tournaments import get_round_participant_hole_history

from tests.conftest import (
    add_membership,
    create_hole,
    create_org,
    create_org_hole,
    create_course,
    create_participant,
    create_player,
    create_round,
    create_tee,
    create_tournament,
    create_tournament_participant,
    create_tournament_round,
    create_tournament_round_participant,
    create_user,
)

import app.db as app_db


# ---------------------------------------------------------------------------
# 1. summarize_hole_history() -- ren funksjon, ingen db.
# ---------------------------------------------------------------------------

def _instance(**overrides) -> HoleInstance:
    defaults = dict(
        source="personal",
        played_at=date(2026, 1, 1),
        label="Runde",
        score=4,
        par=4,
        putts=None,
        tee_shot_result=None,
        approach_result=None,
        chip_count=None,
        bunker_shot_count=None,
        penalty_strokes=None,
        first_putt_distance_bucket=None,
    )
    defaults.update(overrides)
    return HoleInstance(**defaults)


def test_summarize_empty_returns_none():
    assert summarize_hole_history([]) is None


def test_summarize_counts_and_averages():
    instances = [
        _instance(source="personal", score=4, par=4),
        _instance(source="tournament", score=6, par=4),
    ]
    out = summarize_hole_history(instances)
    assert out.times_played == 2
    assert out.times_personal == 1
    assert out.times_tournament == 1
    assert out.average_score == 5.0
    assert out.average_score_vs_par == 1.0
    assert out.best_score == 4
    assert out.worst_score == 6


def test_summarize_gir_percent_only_over_rows_with_putts():
    instances = [
        _instance(score=4, par=4, putts=2),  # 4-2=2 <= 4-2=2 -> GIR
        _instance(score=5, par=4, putts=3),  # 5-3=2 <= 2 -> GIR
        _instance(score=6, par=4, putts=None),  # ingen putter registrert -- ekskludert fra GIR%
    ]
    out = summarize_hole_history(instances)
    assert out.gir_percent == 100.0
    assert out.average_putts == 2.5  # snitt kun over de to MED putter registrert


def test_summarize_gir_percent_none_when_no_putts_data_anywhere():
    instances = [_instance(score=4, par=4, putts=None)]
    out = summarize_hole_history(instances)
    assert out.gir_percent is None
    assert out.average_putts is None


def test_summarize_fairway_percent_excludes_par_3_and_missing_data():
    instances = [
        _instance(par=4, tee_shot_result="fairway"),
        _instance(par=4, tee_shot_result="left"),
        _instance(par=3, tee_shot_result="fairway"),  # par 3 -- ekskludert
        _instance(par=5, tee_shot_result=None),  # ingen utslagsdata -- ekskludert
    ]
    out = summarize_hole_history(instances)
    assert out.fairway_hit_percent == 50.0  # 1 av 2 par-4/5-rader MED data


def test_summarize_orders_most_recent_first_and_undated_last():
    instances = [
        _instance(played_at=date(2026, 1, 1), score=4),
        _instance(played_at=date(2026, 6, 1), score=5),
        _instance(played_at=None, score=6),
    ]
    out = summarize_hole_history(instances)
    assert [i.score for i in out.instances] == [5, 4, 6]


# ---------------------------------------------------------------------------
# 2. Integrasjon: bane-bro + eksklusjoner.
# ---------------------------------------------------------------------------

async def _score_personal_hole(round_id, participant_id, user_id, hole_number, score, putts=None):
    user = CurrentUser(user_id=user_id)
    await round_update_hole(
        round_id, participant_id, hole_number,
        RoundHoleUpdate(score=score, putts=putts, expected_version=None),
        user=user,
    )


async def _score_tournament_hole(tournament_id, round_id, rp_id, org_id, user_id, hole_number, score, putts=None):
    user = CurrentUser(user_id=user_id)
    await tournament_update_hole(
        tournament_id, round_id, rp_id, hole_number,
        TournamentHoleUpdate(gross_strokes=score, putts=putts, expected_version=None),
        organization_id=org_id, user=user,
    )


async def test_teeoff_bridge_combines_personal_and_tournament_history(pool):
    """Samme spiller, samme fysiske (teeoff-)bane -- én frittstående runde
    OG én turneringsrunde i en organisasjon spilleren IKKE eier noe i selv
    (kun har en player-rad koblet til app_user der). Historikken må vise
    BEGGE, uansett hvilken side spørringen kommer fra."""
    user_id = await create_user()

    # Frittstående runde -- create_round() sin faste teeoff-bane-fixture
    # (facility='test-facility', course='test-course').
    async with app_db.plain_connection() as conn:
        round_id = await create_round(conn, user_id)
        participant_id = await create_participant(conn, round_id, user_id=user_id, is_owner=True)
        await create_hole(conn, participant_id, hole_number=7, par=4, stroke_index=9)
    await _score_personal_hole(round_id, participant_id, user_id, hole_number=7, score=4, putts=2)

    # Org-turnering på en bane importert med SAMME teeoff-identitet.
    org_id = await create_org()
    await add_membership(org_id, user_id, role="member")
    tournament_id = await create_tournament(org_id)
    course_id = await create_course(org_id)
    async with app_db.org_connection(org_id) as conn:
        await conn.execute(
            "UPDATE course SET source = 'official', external_course_ref = 'test-facility:test-course' WHERE id = $1",
            course_id,
        )
    for n in range(1, 19):
        await create_org_hole(org_id, course_id, hole_number=n, par=4 if n != 7 else 4, stroke_index=n)
    tee_id = await create_tee(org_id, course_id)
    tournament_round_id = await create_tournament_round(org_id, tournament_id, course_id)
    player_id = await create_player(org_id, user_id=user_id)
    tp_id = await create_tournament_participant(org_id, tournament_id, player_id)
    rp_id = await create_tournament_round_participant(org_id, tournament_round_id, tp_id, tee_id)
    await _score_tournament_hole(tournament_id, tournament_round_id, rp_id, org_id, user_id, hole_number=7, score=5, putts=1)

    key = ("teeoff", "test-facility", "test-course")
    combined = await hole_history_for_user(user_id, key, 7)
    assert combined.times_played == 2
    assert combined.times_personal == 1
    assert combined.times_tournament == 1
    assert sorted(i.score for i in combined.instances) == [4, 5]

    # Begge endepunktene skal returnere SAMME kombinerte historikk.
    from_personal_endpoint = await get_hole_history(
        round_id, participant_id, 7, user=CurrentUser(user_id=user_id)
    )
    assert from_personal_endpoint.times_played == 2

    from_tournament_endpoint = await get_round_participant_hole_history(
        tournament_id, tournament_round_id, rp_id, 7, organization_id=org_id
    )
    assert from_tournament_endpoint.times_played == 2


async def test_custom_personal_course_is_excluded(pool):
    """Håndlaget bane (course_source='custom', ingen GolfAPI-kobling) --
    resolve_personal_round_course_key skal returnere None, IKKE en snublende
    match mot noe annet."""
    user_id = await create_user()
    async with app_db.plain_connection() as conn:
        personal_course_id = str(uuid.uuid4())
        await conn.execute(
            "INSERT INTO personal_course (id, created_by_user_id, name) VALUES ($1, $2, 'Hjemmebanen')",
            personal_course_id, user_id,
        )
        for n in range(1, 19):
            await conn.execute(
                "INSERT INTO personal_course_hole (personal_course_id, hole_number, par, stroke_index) "
                "VALUES ($1, $2, 4, $3)",
                personal_course_id, n, n,
            )
        round_id = str(uuid.uuid4())
        await conn.execute(
            """
            INSERT INTO round (id, owner_user_id, course_source, personal_course_id,
                                course_name_snapshot, tee_name_snapshot, played_at)
            VALUES ($1, $2, 'custom', $3, 'Hjemmebanen', 'Gul', CURRENT_DATE)
            """,
            round_id, user_id, personal_course_id,
        )
        key = await resolve_personal_round_course_key(conn, round_id)
    assert key is None


async def test_guest_tournament_participant_has_no_history(pool):
    """player.user_id IS NULL (gjest, aldri registrert/lenket) -- historikk-
    endepunktet skal svare None (ikke feile), samme "skjul panelet"-
    kontrakt som en custom bane."""
    org_id = await create_org()
    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)
    tournament_round_id = await create_tournament_round(org_id, tournament_id, course_id)
    # user_id utelates bevisst -- create_player() sin default er NULL.
    player_id = await create_player(org_id)
    tp_id = await create_tournament_participant(org_id, tournament_id, player_id)
    rp_id = await create_tournament_round_participant(org_id, tournament_round_id, tp_id, tee_id)

    out = await get_round_participant_hole_history(
        tournament_id, tournament_round_id, rp_id, 1, organization_id=org_id
    )
    assert out is None
