"""Phase 8 — Readiness Assessment UI views.

Coverage:
* The list view renders for the entrepreneur owner, the active mentor,
  and a programme officer; an unrelated user gets 403.
* GET on the record view renders the form for staff/mentor and 403s
  otherwise.
* POST with valid scores creates a row and redirects to the list.
* POST with an out-of-range score returns 400 and surfaces the error.
"""
from __future__ import annotations

from datetime import timedelta
from decimal import Decimal

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

from apps.core.permissions.roles import UserRole
from apps.smehub.incubation import services
from apps.smehub.incubation.models import (
    CohortMember,
    Programme,
    ReadinessAssessment,
)
from apps.smehub.onboarding.models import (
    Business,
    BusinessBaseline,
    BusinessStage,
    EntrepreneurProfile,
    RevenueRange,
)
from apps.smehub.onboarding import signals as onb_signals

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


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


@pytest.fixture
def officer():
    return User.objects.create_user(
        email="po-p8@example.com", password="x", role=UserRole.PROGRAMME_OFFICER,
    )


@pytest.fixture
def mentor():
    return User.objects.create_user(
        email="m-p8@example.com", password="x", role=UserRole.MENTOR,
    )


@pytest.fixture
def entrepreneur(admin):
    user = User.objects.create_user(
        email="ent-p8@example.com", password="x", role=UserRole.ENTREPRENEUR,
    )
    profile = EntrepreneurProfile.objects.create(
        user=user, country="UG", organisation="Test U", phone="+25670008",
    )
    profile.verify(by_user=admin)
    profile.save()
    return profile


@pytest.fixture
def cohort_member(admin, officer, entrepreneur, mentor):
    biz = Business.objects.create(
        entrepreneur=entrepreneur, name="P8 Biz",
        sector="Agriculture", business_stage=BusinessStage.MVP, country="UG",
    )
    baseline = BusinessBaseline.objects.create(
        business=biz, business_stage_at_entry=BusinessStage.MVP,
        fte_count=1, pte_count=0,
        revenue_range=RevenueRange.UNDER_1K,
        primary_target_market="Local", geographic_reach="UG",
    )
    biz.verify(by_user=admin)
    biz.save()
    onb_signals.smehub_baseline_initialised.send(
        sender=BusinessBaseline, business=biz, baseline=baseline, entrepreneur=entrepreneur,
    )
    p = services.create_programme(
        officer=officer,
        title="P8 Programme",
        slug="p8-programme",
        target_sectors=["Agriculture"],
        target_stages=["mvp"],
        cohort_size=5,
        duration_weeks=10,
        application_deadline=timezone.now() + timedelta(days=30),
    )
    services.add_rubric_section(p, title="A", weight=Decimal("1"), max_marks=10)
    p.judges.set([User.objects.create_user(email="p8ui-roster-judge@example.com", password="x", role=UserRole.JUDGE)])
    services.publish_programme(p, by_user=officer)
    p = Programme.objects.get(pk=p.pk)
    app = services.start_application(entrepreneur=entrepreneur, business=biz, programme=p)
    app.business_description = "Test Biz supplies inputs to smallholder farmers."
    app.problem_statement = "Smallholders lack reliable access to quality inputs."
    app.save()
    services.submit_application(app)
    judges = [
        User.objects.create_user(
            email=f"j-p8-{i}@example.com", password="x", role=UserRole.JUDGE,
        )
        for i in range(2)
    ]
    services.assign_judges(app, judges=judges, by_user=officer)
    sections = list(p.rubric.sections.all())
    for j in judges:
        services.submit_score(app, judge=j, section_scores={s.pk: 8 for s in sections})
    cohort = services.confirm_cohort(
        p, accepted_application_ids=[app.pk], name="C-P8",
        start_date=timezone.now().date(),
        end_date=timezone.now().date() + timedelta(days=84),
        by_user=officer,
    )
    member = cohort.members.first()
    services.assign_mentor(member, mentor=mentor, by_user=officer)
    return member


def _login(client, user):
    client.force_login(user)


def test_readiness_list_renders_for_owner(client, cohort_member, entrepreneur):
    _login(client, entrepreneur.user)
    resp = client.get(
        reverse("smehub_incubation:readiness_list", kwargs={"pk": cohort_member.pk}),
    )
    assert resp.status_code == 200


def test_readiness_list_renders_for_mentor(client, cohort_member, mentor):
    _login(client, mentor)
    resp = client.get(
        reverse("smehub_incubation:readiness_list", kwargs={"pk": cohort_member.pk}),
    )
    assert resp.status_code == 200


def test_readiness_list_renders_for_officer(client, cohort_member, officer):
    _login(client, officer)
    resp = client.get(
        reverse("smehub_incubation:readiness_list", kwargs={"pk": cohort_member.pk}),
    )
    assert resp.status_code == 200


def test_readiness_list_blocks_unrelated_user(client, cohort_member):
    other = User.objects.create_user(
        email="other-p8@example.com", password="x", role=UserRole.ENTREPRENEUR,
    )
    _login(client, other)
    resp = client.get(
        reverse("smehub_incubation:readiness_list", kwargs={"pk": cohort_member.pk}),
    )
    assert resp.status_code == 403


def test_record_view_blocks_entrepreneur_owner(client, cohort_member, entrepreneur):
    """Entrepreneurs view their own assessments but cannot record them."""
    _login(client, entrepreneur.user)
    resp = client.get(
        reverse("smehub_incubation:readiness_record", kwargs={"pk": cohort_member.pk}),
    )
    assert resp.status_code == 403


def test_record_view_post_creates_assessment(client, cohort_member, mentor):
    _login(client, mentor)
    resp = client.post(
        reverse("smehub_incubation:readiness_record", kwargs={"pk": cohort_member.pk}),
        data={
            "market_positioning_score": 4,
            "technical_robustness_score": 3,
            "regulatory_compliance_score": 5,
            "overall_notes": "Solid all round.",
        },
    )
    assert resp.status_code == 302
    assert ReadinessAssessment.objects.filter(cohort_member=cohort_member).count() == 1


def test_record_view_rejects_out_of_range(client, cohort_member, mentor):
    _login(client, mentor)
    resp = client.post(
        reverse("smehub_incubation:readiness_record", kwargs={"pk": cohort_member.pk}),
        data={
            "market_positioning_score": 9,
            "technical_robustness_score": 3,
            "regulatory_compliance_score": 3,
        },
    )
    assert resp.status_code == 400
    assert ReadinessAssessment.objects.filter(cohort_member=cohort_member).count() == 0
