"""WS2 defects #2 (dashboard drill-down FieldError) + #16 (viewer-tier gate).

#2 — /mel/events/dashboard/ used to 500 with
``FieldError: Unsupported lookup 'business__sector'`` when a sector/country/AIH
filter was applied, because the cross-module reach block filtered Participants
via an invalid ``entrepreneur_profile__business__…`` path. The valid path runs
through the EntrepreneurProfile's SMEHubTrackingRecord.

#16 — the dashboard now admits the read-only viewer tier
(program_manager / program_director / grants_manager) but hides write CTAs.
"""
from __future__ import annotations

from decimal import Decimal

import pytest
from django.contrib.auth import get_user_model
from django.urls import reverse

from apps.core.authentication.models import Institution
from apps.core.permissions.roles import UserRole
from apps.mel.tracking.models import (
    Participant,
    ParticipantPersona,
    SMEHubTrackingRecord,
)
from apps.smehub.onboarding.models import (
    AIHAffiliation,
    Business,
    BusinessStage,
    EntrepreneurProfile,
)

User = get_user_model()
pytestmark = pytest.mark.django_db


@pytest.fixture
def admin():
    return User.objects.create_user(
        email="ws2-adm@example.com", password="x",
        is_superuser=True, is_staff=True, role=UserRole.SYSTEM_ADMIN,
    )


@pytest.fixture
def mel_officer():
    return User.objects.create_user(
        email="ws2-mel@example.com", password="x", role=UserRole.MEL_OFFICER,
    )


def _entrepreneur(email, country, admin):
    user = User.objects.create_user(email=email, password="x", role=UserRole.ENTREPRENEUR)
    profile = EntrepreneurProfile.objects.create(user=user, country=country, organisation="Co")
    profile.verify(by_user=admin)
    profile.save()
    return user, profile


def _business(profile, name, sector, country, admin):
    biz = Business.objects.create(
        entrepreneur=profile, name=name, sector=sector,
        business_stage=BusinessStage.MVP, country=country,
    )
    biz.verify(by_user=admin)
    biz.save()
    return biz


@pytest.fixture
def portfolio(admin):
    """Two SME-Hub participants: Agriculture/UG and Technology/KE."""
    u1, e1 = _entrepreneur("ws2-e1@example.com", "UG", admin)
    b1 = _business(e1, "Agri Co", "Agriculture", "UG", admin)
    SMEHubTrackingRecord.objects.create(
        entrepreneur=e1, business=b1, funding_secured_total=Decimal("100000"),
    )
    p1 = Participant.objects.create(
        user=u1, entrepreneur_profile=e1,
        personas=[ParticipantPersona.ENTREPRENEUR],
        primary_persona=ParticipantPersona.ENTREPRENEUR,
    )

    u2, e2 = _entrepreneur("ws2-e2@example.com", "KE", admin)
    b2 = _business(e2, "Tech Co", "Technology", "KE", admin)
    SMEHubTrackingRecord.objects.create(
        entrepreneur=e2, business=b2, funding_secured_total=Decimal("50000"),
    )
    p2 = Participant.objects.create(
        user=u2, entrepreneur_profile=e2,
        personas=[ParticipantPersona.ENTREPRENEUR],
        primary_persona=ParticipantPersona.ENTREPRENEUR,
    )

    inst = Institution.objects.create(name="Makerere University")
    AIHAffiliation.objects.create(
        business=b1, institution=inst,
        nature=AIHAffiliation.AffiliationNature.STUDENT, is_primary=True,
    )
    return {"p1": p1, "p2": p2, "b1": b1, "b2": b2, "institution": inst}


def _url():
    return reverse("mel_tracking:tracking_dashboard")


def test_sector_filter_returns_200_and_narrows(client, mel_officer, portfolio):
    client.force_login(mel_officer)
    resp = client.get(_url() + "?sector=Agriculture")
    assert resp.status_code == 200
    assert resp.context["totals"]["participants"] == 1


def test_country_filter_returns_200_and_narrows(client, mel_officer, portfolio):
    client.force_login(mel_officer)
    resp = client.get(_url() + "?country=KE")
    assert resp.status_code == 200
    assert resp.context["totals"]["participants"] == 1


def test_aih_filter_returns_200_and_narrows(client, mel_officer, portfolio):
    client.force_login(mel_officer)
    resp = client.get(_url() + f"?aih={portfolio['institution'].pk}")
    assert resp.status_code == 200
    # Only b1 carries the affiliation, so exactly one participant matches.
    assert resp.context["totals"]["participants"] == 1


def test_cohort_and_period_filters_do_not_crash(client, mel_officer, portfolio):
    client.force_login(mel_officer)
    # Unmatched cohort id: must 200 (not FieldError / 500), narrowing to zero.
    resp = client.get(_url() + "?cohort=999999")
    assert resp.status_code == 200
    resp2 = client.get(_url() + "?period=2026Q1")
    assert resp2.status_code == 200


# --- #16 viewer tier ------------------------------------------------------


@pytest.mark.parametrize(
    "role",
    [UserRole.PROGRAM_MANAGER, UserRole.PROGRAM_DIRECTOR, UserRole.GRANTS_MANAGER],
)
def test_viewer_tier_gets_200(client, portfolio, role):
    viewer = User.objects.create_user(email=f"ws2-{role}@example.com", password="x", role=role)
    client.force_login(viewer)
    resp = client.get(_url())
    assert resp.status_code == 200
    # Read-only: write CTAs are gated off.
    assert resp.context["can_manage_mel"] is False


def test_officer_can_manage(client, mel_officer, portfolio):
    client.force_login(mel_officer)
    resp = client.get(_url())
    assert resp.status_code == 200
    assert resp.context["can_manage_mel"] is True
    # Officer sees the data-entry write CTA; viewer does not.
    assert reverse("mel_indicators:data_entry").encode() in resp.content


def test_viewer_does_not_see_write_cta(client, portfolio):
    viewer = User.objects.create_user(
        email="ws2-pm2@example.com", password="x", role=UserRole.PROGRAM_MANAGER,
    )
    client.force_login(viewer)
    resp = client.get(_url())
    assert resp.status_code == 200
    assert reverse("mel_tracking:mel_configuration").encode() not in resp.content
