"""Phase 7C — repository linkage + mentorship readiness + regulatory navigation.

Coverage targets the prose features in PRD §5.X.X that don't have an
explicit FRSME-XYZ code:

  • Repository linkage — ``relevant_repository_documents`` returns
    published, sector-tagged Repository documents and skips restricted /
    internal visibility.
  • Mentorship Readiness Assessment — ``record_readiness_assessment``
    persists a row with bounded scores, computes ``average_score``, and
    surfaces dimensions falling at/below threshold via ``gaps()``.
  • Regulatory & Policy Navigation — ``relevant_regulatory_guides``
    matches by sector and country (with empty list = universal), and
    skips inactive guides.
"""
from __future__ import annotations

from datetime import timedelta
from decimal import Decimal

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

from apps.core.permissions.roles import UserRole
from apps.repository.documents.models import Collection, Document, Keyword
from apps.smehub._shared.repository import relevant_repository_documents
from apps.smehub.incubation import services as inc_services
from apps.smehub.incubation.models import Programme, ReadinessAssessment
from apps.smehub.linkage import services as lnk_services
from apps.smehub.linkage.models import RegulatoryGuide
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


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------

@pytest.fixture
def admin():
    return User.objects.create_user(
        email="adm-7c@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-7c@example.com", password="x", role=UserRole.PROGRAMME_OFFICER,
    )


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


@pytest.fixture
def business(entrepreneur, admin):
    biz = Business.objects.create(
        entrepreneur=entrepreneur,
        name="Phase 7C Biz",
        sector="Agriculture",
        business_stage=BusinessStage.MVP,
        country="Uganda",
    )
    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,
    )
    return biz


# ---------------------------------------------------------------------------
# Repository linkage
# ---------------------------------------------------------------------------

@pytest.fixture
def repository_collection():
    return Collection.objects.create(
        name="P7C Collection",
        slug="p7c-collection",
    )


_doc_seq = {"n": 0}


def _make_document(*, collection, title, status, keywords=(), visibility=None):
    _doc_seq["n"] += 1
    doc = Document.objects.create(
        title=title,
        collection=collection,
        public_document_id=f"P7C-{_doc_seq['n']:04d}",
        status=status,
        document_type=Document.DocumentType.OTHER,
        visibility=visibility or Document.Visibility.PUBLIC_OPEN,
        year=2025,
    )
    if keywords:
        doc.keywords.set(keywords)
    return doc


def test_relevant_repository_documents_matches_sector_keyword(business, repository_collection):
    kw = Keyword.objects.create(
        label="Agriculture", slug="agriculture",
        status=Keyword.Status.APPROVED,
    )
    matched = _make_document(
        collection=repository_collection, title="Soil practices",
        status=Document.Status.PUBLISHED, keywords=[kw],
    )
    _make_document(  # off-topic, no keywords → not matched
        collection=repository_collection, title="Mining safety",
        status=Document.Status.PUBLISHED,
    )
    results = list(relevant_repository_documents(business))
    assert matched in results


def test_relevant_repository_documents_skips_restricted_and_unpublished(
    business, repository_collection,
):
    kw = Keyword.objects.create(
        label="Agriculture", slug="agriculture",
        status=Keyword.Status.APPROVED,
    )
    _make_document(
        collection=repository_collection, title="Restricted",
        status=Document.Status.PUBLISHED, keywords=[kw],
        visibility=Document.Visibility.RESTRICTED,
    )
    _make_document(
        collection=repository_collection, title="Internal",
        status=Document.Status.PUBLISHED, keywords=[kw],
        visibility=Document.Visibility.INTERNAL,
    )
    _make_document(
        collection=repository_collection, title="Draft",
        status=Document.Status.DRAFT, keywords=[kw],
    )
    public = _make_document(
        collection=repository_collection, title="Public",
        status=Document.Status.PUBLISHED, keywords=[kw],
    )
    results = list(relevant_repository_documents(business))
    assert results == [public]


def test_relevant_repository_documents_returns_empty_without_sector(business):
    business.sector = ""
    business.save(update_fields=["sector"])
    assert relevant_repository_documents(business) == []


# ---------------------------------------------------------------------------
# Mentorship Readiness Assessment
# ---------------------------------------------------------------------------

@pytest.fixture
def cohort_member(business, entrepreneur, officer):
    p = inc_services.create_programme(
        officer=officer,
        title="P7C Programme",
        slug="p7c-programme",
        target_sectors=["Agriculture"],
        target_stages=["mvp"],
        cohort_size=5,
        duration_weeks=10,
        application_deadline=timezone.now() + timedelta(days=30),
    )
    inc_services.add_rubric_section(p, title="A", weight=Decimal("0.5"), max_marks=10)
    inc_services.add_rubric_section(p, title="B", weight=Decimal("0.5"), max_marks=10)
    p.judges.set([User.objects.create_user(email="p7c-roster-judge@example.com", password="x", role=UserRole.JUDGE)])
    inc_services.publish_programme(p, by_user=officer)
    p = Programme.objects.get(pk=p.pk)

    app = inc_services.start_application(
        entrepreneur=entrepreneur, business=business, programme=p,
    )
    app.business_description = "Test Biz supplies inputs to smallholder farmers."
    app.problem_statement = "Smallholders lack reliable access to quality inputs."
    app.save()
    inc_services.submit_application(app)
    judges = [
        User.objects.create_user(
            email=f"j-7c-{i}@example.com", password="x", role=UserRole.JUDGE,
        )
        for i in range(2)
    ]
    inc_services.assign_judges(app, judges=judges, by_user=officer)
    sections = list(p.rubric.sections.all())
    for judge in judges:
        inc_services.submit_score(app, judge=judge, section_scores={s.pk: 8 for s in sections})
    cohort = inc_services.confirm_cohort(
        p, accepted_application_ids=[app.pk], name="C7C",
        start_date=timezone.now().date(),
        end_date=timezone.now().date() + timedelta(days=84),
        by_user=officer,
    )
    return cohort.members.first()


def test_record_readiness_assessment_persists_and_computes_average(cohort_member, admin):
    a = inc_services.record_readiness_assessment(
        cohort_member,
        market_positioning_score=4,
        technical_robustness_score=3,
        regulatory_compliance_score=5,
        by_user=admin,
        overall_notes="Looking good overall.",
    )
    assert a.pk
    assert a.average_score == Decimal("4.00")
    assert ReadinessAssessment.objects.filter(cohort_member=cohort_member).count() == 1


def test_readiness_gaps_lists_dimensions_at_or_below_threshold(cohort_member, admin):
    a = inc_services.record_readiness_assessment(
        cohort_member,
        market_positioning_score=2,
        technical_robustness_score=4,
        regulatory_compliance_score=3,
        by_user=admin,
    )
    gaps = a.gaps()
    assert "market_positioning" in gaps
    assert "regulatory_compliance" in gaps
    assert "technical_robustness" not in gaps


def test_readiness_rejects_out_of_range_scores(cohort_member, admin):
    with pytest.raises(inc_services.IncubationStateError):
        inc_services.record_readiness_assessment(
            cohort_member,
            market_positioning_score=7,
            technical_robustness_score=3,
            regulatory_compliance_score=3,
            by_user=admin,
        )
    with pytest.raises(inc_services.IncubationStateError):
        inc_services.record_readiness_assessment(
            cohort_member,
            market_positioning_score=3,
            technical_robustness_score=0,
            regulatory_compliance_score=3,
            by_user=admin,
        )


# ---------------------------------------------------------------------------
# Regulatory & Policy Navigation
# ---------------------------------------------------------------------------

def test_regulatory_guides_match_sector_and_country(business):
    matched = RegulatoryGuide.objects.create(
        title="UG Agro Standards",
        slug="ug-agro-standards",
        body_type=RegulatoryGuide.BodyType.STANDARD,
        sectors=["Agriculture"],
        countries=["Uganda"],
        summary="x",
    )
    universal = RegulatoryGuide.objects.create(
        title="Regional Policy Brief",
        slug="regional-policy",
        body_type=RegulatoryGuide.BodyType.POLICY,
        sectors=[],
        countries=[],
        summary="x",
    )
    RegulatoryGuide.objects.create(  # off-topic — Health/KE
        title="KE Health Approvals",
        slug="ke-health-approvals",
        body_type=RegulatoryGuide.BodyType.APPROVAL,
        sectors=["Health"],
        countries=["Kenya"],
        summary="x",
    )
    results = list(lnk_services.relevant_regulatory_guides(business))
    assert matched in results
    assert universal in results
    assert all(r.body_type != RegulatoryGuide.BodyType.APPROVAL for r in results)


def test_regulatory_guides_skip_inactive(business):
    inactive = RegulatoryGuide.objects.create(
        title="Deprecated",
        slug="deprecated",
        body_type=RegulatoryGuide.BodyType.OTHER,
        sectors=["Agriculture"],
        countries=["Uganda"],
        summary="x",
        is_active=False,
    )
    results = list(lnk_services.relevant_regulatory_guides(business))
    assert inactive not in results
