"""G16 — pre-due survey reminder beat tests."""
from __future__ import annotations

from datetime import timedelta

import pytest
from django.contrib.auth import get_user_model
from django.utils import timezone

from apps.mel.feedback.models import Survey, SurveyDispatch, SurveyStatus
from apps.mel.feedback.tasks import scan_due_survey_reminders

pytestmark = pytest.mark.django_db(transaction=True)

User = get_user_model()


def _make_survey(slug: str = "g16-survey") -> Survey:
    return Survey.objects.create(
        title="G16 survey",
        slug=slug,
        status=SurveyStatus.ACTIVE,
        response_window_days=14,
    )


def _dispatch(survey: Survey, *, due_in_hours: float, recipient=None) -> SurveyDispatch:
    return SurveyDispatch.objects.create(
        survey=survey,
        recipient=recipient,
        recipient_email="" if recipient else "external@example.com",
        token=SurveyDispatch.generate_token() if hasattr(SurveyDispatch, "generate_token") else f"tok-{timezone.now().timestamp()}",
        due_at=timezone.now() + timedelta(hours=due_in_hours),
    )


def test_pre_due_reminder_fires_within_48h_window():
    survey = _make_survey()
    user = User.objects.create_user(email="g16-reminded@example.com", password="x")
    d = _dispatch(survey, due_in_hours=47, recipient=user)

    result = scan_due_survey_reminders()

    assert result == {"reminded": 1}
    d.refresh_from_db()
    assert d.status == SurveyDispatch.Status.REMINDED
    assert d.reminded_at is not None


def test_pre_due_reminder_does_not_fire_outside_window():
    survey = _make_survey("g16-outside")
    user = User.objects.create_user(email="g16-outside@example.com", password="x")
    _dispatch(survey, due_in_hours=72, recipient=user)  # still > 48h away

    result = scan_due_survey_reminders()

    assert result == {"reminded": 0}


def test_pre_due_reminder_is_idempotent_once_reminded():
    survey = _make_survey("g16-idem")
    user = User.objects.create_user(email="g16-idem@example.com", password="x")
    d = _dispatch(survey, due_in_hours=24, recipient=user)

    first = scan_due_survey_reminders()
    second = scan_due_survey_reminders()

    assert first == {"reminded": 1}
    assert second == {"reminded": 0}
    d.refresh_from_db()
    assert d.reminded_at is not None


def test_pre_due_reminder_skips_past_due_dispatches():
    """Once due_at has passed, the *post-due* sweep handles it — pre-due must not fire."""
    survey = _make_survey("g16-past")
    user = User.objects.create_user(email="g16-past@example.com", password="x")
    _dispatch(survey, due_in_hours=-1, recipient=user)

    result = scan_due_survey_reminders()

    assert result == {"reminded": 0}
