import datetime

import pytest
from django.contrib.auth import get_user_model

from apps.core.authentication.models import Institution, UserProfile
from apps.core.permissions.roles import UserRole

User = get_user_model()


@pytest.fixture
def institution(db):
    return Institution.objects.create(name="Phase1 Test University", country="Uganda", is_member=True)


@pytest.fixture
def applicant_user(db, institution):
    """A "ready to apply" applicant — profile fields required by
    apps.rims.grants.profile_gate.ProfileCompleteRequiredMixin are all
    populated, since most of the suite exercises apply-flow views that this
    gate now guards. Tests that specifically need an incomplete profile
    should use `incomplete_profile_applicant_user` instead."""
    u = User.objects.create_user(email="applicant.phase1@example.com", password="pw-phase1")
    u.institution = institution
    u.role = UserRole.SCHOLAR
    u.first_name = "Applicant"
    u.last_name = "One"
    u.phone = "+256700000001"
    u.save()
    # Mutate u.profile in place (not a fresh UserProfile.objects.get_or_create()
    # fetch) — the post_save signal that auto-creates the blank profile also
    # populates Django's reverse-o2o cache on `u` (setting the forward side of
    # a OneToOneField caches the reverse accessor too), so a separately
    # fetched instance would silently diverge from what `u.profile` returns
    # afterwards.
    profile = u.profile
    profile.country = "Uganda"
    profile.degree_level = UserProfile.DegreeLevel.MASTERS
    profile.date_of_birth = datetime.date(1995, 1, 1)
    profile.areas_of_interest = "agritech"
    profile.save()
    return u


@pytest.fixture
def incomplete_profile_applicant_user(db, institution):
    """An applicant who hasn't filled in their profile yet — for testing
    apps.rims.grants.profile_gate's hard block and dashboard nudge."""
    u = User.objects.create_user(email="applicant.incomplete@example.com", password="pw-phase1")
    u.institution = institution
    u.role = UserRole.SCHOLAR
    u.save()
    return u


@pytest.fixture
def grants_manager_user(db, institution):
    u = User.objects.create_user(email="gm.phase1@example.com", password="pw-phase1")
    u.institution = institution
    u.role = UserRole.GRANTS_MANAGER
    u.save()
    return u


@pytest.fixture
def reviewer_user(db, institution):
    u = User.objects.create_user(email="rev.phase1@example.com", password="pw-phase1")
    u.role = UserRole.REVIEWER
    u.save()
    return u


@pytest.fixture
def finance_user(db, institution):
    u = User.objects.create_user(email="fo.phase1@example.com", password="pw-phase1")
    u.role = UserRole.FINANCE_OFFICER
    u.save()
    return u
