from __future__ import annotations

from datetime import timedelta

import pytest
from django.core.exceptions import ValidationError
from django.utils import timezone

from apps.alumni.engagement.models import (
    AlumniEvent,
    EventRegistration,
    EventVisibility,
    GroupMembership,
    MentorshipPairing,
    MentorshipStatus,
    NetworkGroup,
)
from apps.alumni.engagement.services import (
    join_group,
    leave_group,
    register_for_event,
    request_mentorship,
    respond_to_mentorship,
    send_due_event_reminders,
)
from apps.alumni.profiles.models import AlumniProfile


@pytest.mark.django_db
def test_register_for_event_enforces_capacity(alumni_user, scholar_user):
    event = AlumniEvent.objects.create(
        title="Capacity test",
        start_at=timezone.now() + timedelta(days=1),
        end_at=timezone.now() + timedelta(days=1, hours=2),
        capacity=1,
        visibility=EventVisibility.PUBLIC,
    )
    register_for_event(alumni_user, event)
    with pytest.raises(ValidationError):
        register_for_event(scholar_user, event)


@pytest.mark.django_db
def test_group_join_leave_updates_counter(alumni_user):
    group = NetworkGroup.objects.create(title="Test Chapter")
    join_group(alumni_user, group)
    group.refresh_from_db()
    assert group.member_count == 1
    assert GroupMembership.objects.filter(user=alumni_user, group=group).exists()
    leave_group(alumni_user, group)
    group.refresh_from_db()
    assert group.member_count == 0


@pytest.mark.django_db
def test_request_and_accept_mentorship(alumni_user, scholar_user):
    mentor_profile = AlumniProfile.objects.create(
        user=alumni_user, mentor_accepting=True
    )
    pairing = request_mentorship(scholar_user, mentor_profile, topic="Research methods")
    assert pairing.status == MentorshipStatus.REQUESTED
    respond_to_mentorship(pairing, accept=True)
    pairing.refresh_from_db()
    assert pairing.status == MentorshipStatus.ACTIVE
    assert pairing.started_at is not None


@pytest.mark.django_db
def test_cannot_self_mentor(alumni_user):
    mentor_profile = AlumniProfile.objects.create(
        user=alumni_user, mentor_accepting=True
    )
    with pytest.raises(ValidationError):
        request_mentorship(alumni_user, mentor_profile, topic="Self")


@pytest.mark.django_db
def test_request_blocked_when_mentor_not_accepting(alumni_user, scholar_user):
    mentor_profile = AlumniProfile.objects.create(
        user=alumni_user, mentor_accepting=False
    )
    with pytest.raises(ValidationError):
        request_mentorship(scholar_user, mentor_profile, topic="x")


@pytest.mark.django_db
def test_request_blocked_at_capacity(alumni_user, scholar_user, institution):
    from django.contrib.auth import get_user_model

    User = get_user_model()
    mentor_profile = AlumniProfile.objects.create(
        user=alumni_user, mentor_accepting=True, mentor_capacity=1
    )
    other = User.objects.create_user(email="other@example.com", password="pw")
    # Saturate the mentor's capacity with an existing ACTIVE pairing.
    from apps.alumni.engagement.models import MentorshipPairing
    MentorshipPairing.objects.create(
        mentor=mentor_profile, mentee=other, status=MentorshipStatus.ACTIVE
    )
    with pytest.raises(ValidationError):
        request_mentorship(scholar_user, mentor_profile, topic="overflow")


@pytest.mark.django_db
def test_log_session_and_complete(alumni_user, scholar_user):
    from apps.alumni.engagement.services import complete_mentorship, log_session
    from apps.alumni.engagement.models import MentorshipPairing

    mentor_profile = AlumniProfile.objects.create(
        user=alumni_user, mentor_accepting=True
    )
    pairing = MentorshipPairing.objects.create(
        mentor=mentor_profile,
        mentee=scholar_user,
        status=MentorshipStatus.ACTIVE,
        started_at=timezone.now(),
    )
    note = log_session(pairing, alumni_user, "<p>First session.</p>")
    assert note.pk is not None
    assert pairing.session_notes.count() == 1
    complete_mentorship(
        pairing, outcome="<p>Mentee landed a postdoc.</p>", outcome_rating=5, completed_by=alumni_user
    )
    pairing.refresh_from_db()
    assert pairing.status == MentorshipStatus.COMPLETED
    assert pairing.outcome_rating == 5
    assert pairing.ended_at is not None


@pytest.mark.django_db
def test_withdraw_mentorship_request(alumni_user, scholar_user):
    from apps.alumni.engagement.services import withdraw_mentorship_request

    mentor_profile = AlumniProfile.objects.create(
        user=alumni_user, mentor_accepting=True
    )
    pairing = request_mentorship(scholar_user, mentor_profile, topic="t")
    withdraw_mentorship_request(pairing, by_user=scholar_user)
    pairing.refresh_from_db()
    assert pairing.status == MentorshipStatus.CANCELLED
    # Cannot withdraw again
    with pytest.raises(ValidationError):
        withdraw_mentorship_request(pairing, by_user=scholar_user)


@pytest.mark.django_db
def test_send_event_reminders_stamp_reminder_once(alumni_user):
    soon = timezone.now() + timedelta(hours=6)
    event = AlumniEvent.objects.create(
        title="Soon",
        start_at=soon,
        end_at=soon + timedelta(hours=1),
        visibility=EventVisibility.PUBLIC,
    )
    EventRegistration.objects.create(user=alumni_user, event=event)
    sent_first = send_due_event_reminders()
    sent_second = send_due_event_reminders()
    assert sent_first == 1
    assert sent_second == 0
