"""
Rundespesifikk kommentartråd for org-turneringer (ADR-102). Ekte parallell
til round_messages.py sin RoundMessages, men org-scopet (RLS) i stedet for
plain_connection() -- skriverett = leserett = org-medlemskap
(get_authorized_org), moderering = forfatter ELLER org-admin (is_org_admin),
samme regel som Banter Board (ADR-025). Én tråd PER TURNERINGSRUNDE (hele
feltet deler tråd, ikke per flight).
"""

import uuid

import pytest
from fastapi import HTTPException

from app.auth import CurrentUser
from app.routers.tournament_round_messages import (
    CommentIn,
    ReactionIn,
    delete_tournament_round_message,
    delete_tournament_round_message_comment,
    list_tournament_round_message_comments,
    list_tournament_round_messages,
    post_tournament_round_message,
    post_tournament_round_message_comment,
    remove_tournament_round_message_reaction,
    set_tournament_round_message_reaction,
)

from tests.conftest import (
    add_membership,
    create_org,
    create_tournament,
    create_tournament_round,
    create_course,
    create_user,
)


async def _setup(org_id):
    tournament_id = await create_tournament(org_id, name="Kommentar-turnering")
    course_id = await create_course(org_id, name="Kommentarbanen")
    round_id = await create_tournament_round(org_id, tournament_id, course_id, sequence=1)
    return tournament_id, round_id


async def test_post_and_list_message(pool):
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user(display_name="Forfatter Testesen")
    await add_membership(org_id, author_id)

    created = await post_tournament_round_message(
        tournament_id, round_id, body="Fin runde i dag!", image=None, client_message_id=None,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    assert created.body == "Fin runde i dag!"
    assert created.tournament_round_id == round_id
    assert created.author_display_name == "Forfatter Testesen"

    listed = await list_tournament_round_messages(
        tournament_id, round_id, organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    assert [m.id for m in listed] == [created.id]


async def test_client_message_id_idempotent(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user()
    await add_membership(org_id, author_id)

    client_message_id = str(uuid.uuid4())
    first = await post_tournament_round_message(
        tournament_id, round_id, body="Duplikat-test", image=None, client_message_id=client_message_id,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    second = await post_tournament_round_message(
        tournament_id, round_id, body="Duplikat-test", image=None, client_message_id=client_message_id,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    assert first.id == second.id

    listed = await list_tournament_round_messages(
        tournament_id, round_id, organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    assert len(listed) == 1


async def test_body_or_image_required(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user()
    await add_membership(org_id, author_id)

    with pytest.raises(HTTPException) as exc_info:
        await post_tournament_round_message(
            tournament_id, round_id, body=None, image=None, client_message_id=None,
            organization_id=org_id, user=CurrentUser(user_id=author_id),
        )
    assert exc_info.value.status_code == 400


async def test_wrong_tournament_id_404(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    other_tournament_id = await create_tournament(org_id, name="En annen turnering")
    author_id = await create_user()
    await add_membership(org_id, author_id)

    with pytest.raises(HTTPException) as exc_info:
        await post_tournament_round_message(
            other_tournament_id, round_id, body="Feil turnering", image=None, client_message_id=None,
            organization_id=org_id, user=CurrentUser(user_id=author_id),
        )
    assert exc_info.value.status_code == 404


async def test_rls_blocks_cross_org_access(pool) -> None:
    org_a = await create_org()
    org_b = await create_org()
    tournament_id, round_id = await _setup(org_a)
    author_id = await create_user()
    await add_membership(org_a, author_id)
    await add_membership(org_b, author_id)

    await post_tournament_round_message(
        tournament_id, round_id, body="Kun org A", image=None, client_message_id=None,
        organization_id=org_a, user=CurrentUser(user_id=author_id),
    )

    # Samme (tournament_id, round_id) forsøkt lest med FEIL org_id satt --
    # RLS filtrerer bort tournament_round-raden, _get_tournament_round_or_404
    # ser den derfor ikke og gir 404 (ikke et 0-treffs, "tom liste"-svar).
    with pytest.raises(HTTPException) as exc_info:
        await list_tournament_round_messages(
            tournament_id, round_id, organization_id=org_b, user=CurrentUser(user_id=author_id),
        )
    assert exc_info.value.status_code == 404


async def test_delete_by_author(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user()
    await add_membership(org_id, author_id)

    created = await post_tournament_round_message(
        tournament_id, round_id, body="Slett meg", image=None, client_message_id=None,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    await delete_tournament_round_message(
        tournament_id, round_id, created.id, organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    listed = await list_tournament_round_messages(
        tournament_id, round_id, organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    assert listed == []


async def test_delete_by_org_admin_not_author(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user()
    admin_id = await create_user()
    await add_membership(org_id, author_id, role="member")
    await add_membership(org_id, admin_id, role="admin")

    created = await post_tournament_round_message(
        tournament_id, round_id, body="Slett meg som admin", image=None, client_message_id=None,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    await delete_tournament_round_message(
        tournament_id, round_id, created.id, organization_id=org_id, user=CurrentUser(user_id=admin_id),
    )
    listed = await list_tournament_round_messages(
        tournament_id, round_id, organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    assert listed == []


async def test_delete_rejected_for_unrelated_member(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user()
    other_member_id = await create_user()
    await add_membership(org_id, author_id, role="member")
    await add_membership(org_id, other_member_id, role="member")

    created = await post_tournament_round_message(
        tournament_id, round_id, body="Ikke slett meg", image=None, client_message_id=None,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    with pytest.raises(HTTPException) as exc_info:
        await delete_tournament_round_message(
            tournament_id, round_id, created.id, organization_id=org_id, user=CurrentUser(user_id=other_member_id),
        )
    assert exc_info.value.status_code == 403


async def test_ordinary_member_can_post(pool) -> None:
    """Skriverett = org-medlemskap, ikke deltaker-i-akkurat-denne-turneringen
    eller admin -- bekrefter at et VANLIG medlem (ikke admin/deltaker) kan
    poste, samme "vanlig org-medlemsnivå"-presedens som resten av
    individual_tournaments.py sitt oppsett (ADR-102)."""
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    member_id = await create_user()
    await add_membership(org_id, member_id, role="member")

    created = await post_tournament_round_message(
        tournament_id, round_id, body="Jeg er bare medlem", image=None, client_message_id=None,
        organization_id=org_id, user=CurrentUser(user_id=member_id),
    )
    assert created.body == "Jeg er bare medlem"


async def test_reaction_upsert_and_remove(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user()
    reactor_id = await create_user()
    await add_membership(org_id, author_id)
    await add_membership(org_id, reactor_id)

    created = await post_tournament_round_message(
        tournament_id, round_id, body="Reager på meg", image=None, client_message_id=None,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )

    summaries = await set_tournament_round_message_reaction(
        tournament_id, round_id, created.id, ReactionIn(emoji="👍"),
        organization_id=org_id, user=CurrentUser(user_id=reactor_id),
    )
    assert len(summaries) == 1
    assert summaries[0].emoji == "👍"
    assert summaries[0].count == 1
    assert summaries[0].reacted_by_me is True

    # Bytte av emoji erstatter, stables ikke.
    summaries = await set_tournament_round_message_reaction(
        tournament_id, round_id, created.id, ReactionIn(emoji="❤️"),
        organization_id=org_id, user=CurrentUser(user_id=reactor_id),
    )
    assert len(summaries) == 1
    assert summaries[0].emoji == "❤️"

    summaries = await remove_tournament_round_message_reaction(
        tournament_id, round_id, created.id, organization_id=org_id, user=CurrentUser(user_id=reactor_id),
    )
    assert summaries == []


async def test_invalid_emoji_rejected(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user()
    await add_membership(org_id, author_id)
    created = await post_tournament_round_message(
        tournament_id, round_id, body="Test", image=None, client_message_id=None,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )
    with pytest.raises(HTTPException) as exc_info:
        await set_tournament_round_message_reaction(
            tournament_id, round_id, created.id, ReactionIn(emoji="🐸"),
            organization_id=org_id, user=CurrentUser(user_id=author_id),
        )
    assert exc_info.value.status_code == 400


async def test_threaded_comment_create_list_delete(pool) -> None:
    org_id = await create_org()
    tournament_id, round_id = await _setup(org_id)
    author_id = await create_user()
    commenter_id = await create_user()
    admin_id = await create_user()
    await add_membership(org_id, author_id, role="member")
    await add_membership(org_id, commenter_id, role="member")
    await add_membership(org_id, admin_id, role="admin")

    message = await post_tournament_round_message(
        tournament_id, round_id, body="Kommenter meg", image=None, client_message_id=None,
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )

    top_comment = await post_tournament_round_message_comment(
        tournament_id, round_id, message.id, CommentIn(body="Bra spilt!"),
        organization_id=org_id, user=CurrentUser(user_id=commenter_id),
    )
    reply = await post_tournament_round_message_comment(
        tournament_id, round_id, message.id, CommentIn(body="Enig!", parent_comment_id=top_comment.id),
        organization_id=org_id, user=CurrentUser(user_id=author_id),
    )

    comments = await list_tournament_round_message_comments(
        tournament_id, round_id, message.id, organization_id=org_id,
    )
    assert {c.id for c in comments} == {top_comment.id, reply.id}
    assert next(c for c in comments if c.id == reply.id).parent_comment_id == top_comment.id

    # Ikke-forfatter-ikke-admin nektes.
    with pytest.raises(HTTPException) as exc_info:
        await delete_tournament_round_message_comment(
            tournament_id, round_id, message.id, top_comment.id,
            organization_id=org_id, user=CurrentUser(user_id=author_id),
        )
    assert exc_info.value.status_code == 403

    # Org-admin kan slette andres kommentar -- kaskade-sletter svaret under.
    await delete_tournament_round_message_comment(
        tournament_id, round_id, message.id, top_comment.id,
        organization_id=org_id, user=CurrentUser(user_id=admin_id),
    )
    remaining = await list_tournament_round_message_comments(
        tournament_id, round_id, message.id, organization_id=org_id,
    )
    assert remaining == []
