"""Seed SME-Hub incubation (SP2) demo data.

Idempotent. Builds on the SP1 onboarding seeder (must run first):
* 3 programmes — DRAFT, PUBLISHED, CLOSED — each with a 4-section rubric and a
  REP-course link when matching courses exist.
* ~8 applications across statuses (drafts, submitted, under review, returned,
  accepted, rejected).
* 1 confirmed cohort with members, mentor assignments, mixed-status sessions,
  manual training records, and 2 generated certificates.
"""
from __future__ import annotations

import logging
from datetime import date, timedelta
from decimal import Decimal

from django.contrib.auth import get_user_model
from django.contrib.auth.hashers import make_password
from django.db import transaction
from django.utils import timezone
from django.utils.text import slugify

from apps.core.countries import to_country_name
from apps.core.permissions.roles import UserRole
from apps.smehub.incubation.models import (
    Application,
    Cohort,
    CohortMember,
    JudgeAssignment,
    JudgeScore,
    MentorAssignment,
    MentorSession,
    ProgressRecord,
    Programme,
    ProgrammeCourseLink,
    RubricSection,
    ScoringRubric,
)
from apps.smehub.onboarding.models import Business, EntrepreneurProfile

logger = logging.getLogger(__name__)
User = get_user_model()

DEMO_PASSWORD = "smehub-demo-2026"  # noqa: S105 - demo only


def _ensure_user(email: str, *, first: str, last: str, role: str) -> User:
    user, created = User.objects.get_or_create(
        email=email,
        defaults={
            "first_name": first,
            "last_name": last,
            "is_active": True,
            "email_verified": True,
            "role": role,
        },
    )
    if created:
        user.password = make_password(DEMO_PASSWORD)
        user.save(update_fields=["password"])
    return user


_RUBRIC = [
    ("Problem & Market", Decimal("0.30"), 10, "How well-defined is the problem and the target market?"),
    ("Solution & Innovation", Decimal("0.25"), 10, "Novelty and feasibility of the proposed solution."),
    ("Team & Execution", Decimal("0.20"), 10, "Team capability, traction, and execution to date."),
    ("Impact & Sustainability", Decimal("0.25"), 10, "Social, economic, and environmental impact potential."),
]


def _ensure_rubric(programme: Programme) -> ScoringRubric:
    rubric, _ = ScoringRubric.objects.get_or_create(programme=programme)
    if rubric.sections.exists():
        return rubric
    for order, (title, weight, max_marks, instructions) in enumerate(_RUBRIC):
        RubricSection.objects.create(
            rubric=rubric,
            title=title,
            weight=weight,
            max_marks=max_marks,
            instructions=instructions,
            order=order,
        )
    return rubric


def _maybe_link_first_published_course(programme: Programme) -> None:
    # Seed one illustrative Moodle-course link. Courses live in Moodle now, so we
    # attach a placeholder Moodle course id rather than a REP Course row.
    ProgrammeCourseLink.objects.get_or_create(
        programme=programme,
        moodle_course_id="demo-101",
        defaults={
            "course_title": "Demo Moodle course",
            "is_required": True,
            "notes": "Auto-linked by SP2 seeder",
        },
    )


@transaction.atomic
def seed() -> dict:
    counts = {
        "programmes": 0,
        "applications": 0,
        "cohorts": 0,
        "members": 0,
        "judge_assignments": 0,
        "scores": 0,
        "mentor_assignments": 0,
        "sessions": 0,
        "certificates": 0,
    }

    # Programme officer + judges + reuse SP1 mentors --------------------
    officer = _ensure_user(
        "alex.officer@smehub.example",
        first="Alex",
        last="Officer",
        role=UserRole.PROGRAMME_OFFICER,
    )
    judges = [
        _ensure_user(
            f"judge{i}@smehub.example",
            first=f"Judge{i}",
            last="Reviewer",
            role=UserRole.JUDGE,
        )
        for i in range(1, 4)
    ]

    mentors = list(
        User.objects.filter(role=UserRole.MENTOR, email__endswith="@smehub.example").order_by("email")[:3],
    )
    if not mentors:
        logger.warning("SP2 seeder: no SP1 mentors found — run SP1 seeder first for full data.")

    # Programmes -------------------------------------------------------
    today = date.today()
    programme_specs = [
        {
            "title": "Agritech Accelerator 2026",
            "objectives": "12-week intensive for agritech founders post-MVP. Mentorship, REP courses, AIH residency, investor day.",
            "target_sectors": ["Agriculture", "Agribusiness", "Aquaculture"],
            "target_stages": ["mvp", "early_revenue", "growth"],
            "eligibility_countries": [],
            "cohort_size": 12,
            "duration_weeks": 12,
            "aih_locations": ["Makerere AIH", "University of Nairobi AIH"],
            "application_opens_at": timezone.make_aware(timezone.datetime.combine(today - timedelta(days=10), timezone.datetime.min.time())),
            "application_deadline": timezone.make_aware(timezone.datetime.combine(today + timedelta(days=14), timezone.datetime.min.time())),
            "publish": True,
        },
        {
            "title": "Energy & Climate Founders 2026 (Draft)",
            "objectives": "Draft programme for clean-energy ventures — pending rubric review and partner sign-off.",
            "target_sectors": ["Energy"],
            "target_stages": ["idea", "mvp"],
            "eligibility_countries": [],
            "cohort_size": 8,
            "duration_weeks": 16,
            "aih_locations": ["Addis Ababa AIH"],
            "application_opens_at": None,
            "application_deadline": None,
            "publish": False,
        },
        {
            "title": "Coastal Trade Cohort 2025",
            "objectives": "Post-cohort archive for the 2025 coastal-trade incubation cohort.",
            "target_sectors": ["Agribusiness", "Trade"],
            "target_stages": ["growth", "scale"],
            "eligibility_countries": [to_country_name(c) for c in ["KE", "TZ", "MZ"]],
            "cohort_size": 10,
            "duration_weeks": 14,
            "aih_locations": ["Sokoine University AIH"],
            "application_opens_at": timezone.make_aware(timezone.datetime.combine(today - timedelta(days=180), timezone.datetime.min.time())),
            "application_deadline": timezone.make_aware(timezone.datetime.combine(today - timedelta(days=120), timezone.datetime.min.time())),
            "publish": True,
            "close": True,
        },
    ]

    programmes: dict[str, Programme] = {}
    for spec in programme_specs:
        slug = slugify(spec["title"])[:120]
        programme, created = Programme.objects.get_or_create(
            slug=slug,
            defaults={
                "title": spec["title"],
                "objectives": spec["objectives"],
                "target_sectors": spec["target_sectors"],
                "target_stages": spec["target_stages"],
                "eligibility_countries": spec["eligibility_countries"],
                "cohort_size": spec["cohort_size"],
                "duration_weeks": spec["duration_weeks"],
                "aih_locations": spec["aih_locations"],
                "application_opens_at": spec["application_opens_at"],
                "application_deadline": spec["application_deadline"],
                "created_by": officer,
            },
        )
        if created:
            counts["programmes"] += 1
        _ensure_rubric(programme)
        _maybe_link_first_published_course(programme)
        if created and spec.get("publish") and programme.status == Programme.Status.DRAFT:
            programme.publish()
            programme.save()
        if created and spec.get("close") and programme.status == Programme.Status.PUBLISHED:
            programme.close()
            programme.save()
        programmes[spec["title"]] = programme

    # Applications + judging on the published programme ----------------
    accelerator = programmes["Agritech Accelerator 2026"]
    eligible_businesses = list(
        Business.objects.filter(
            verification_status=Business.Status.VERIFIED,
            sector__in=accelerator.target_sectors,
        ).select_related("entrepreneur__user")[:5],
    )

    for idx, biz in enumerate(eligible_businesses):
        app, created = Application.objects.get_or_create(
            programme=accelerator,
            business=biz,
            defaults={
                "entrepreneur": biz.entrepreneur,
                "business_description": f"{biz.name} works on {biz.sub_sector or biz.sector.lower()} solutions.",
                "problem_statement": "Smallholder farmers lack access to reliable inputs and reach to formal markets.",
                "traction": "Pilot revenue, growing customer base, at least one institutional partnership.",
                "funding_needs": "Seeking $50k–$150k for production scale-up and working capital.",
                "support_sought": "Mentorship, market access, REP courses on financial management.",
            },
        )
        if not created:
            continue
        counts["applications"] += 1
        # Spread statuses: draft, submitted, under review, returned, accepted, rejected
        if idx == 0:
            # leave as draft
            continue
        app.submit()
        app.save()
        if idx == 1:
            continue  # submitted
        app.begin_review()
        app.save()
        # assign judges
        for judge in judges:
            ja, _ = JudgeAssignment.objects.get_or_create(application=app, judge=judge)
            ja.notified_at = timezone.now()
            ja.save(update_fields=["notified_at"])
            counts["judge_assignments"] += 1
            # judges score the application
            sections = list(accelerator.rubric.sections.all())
            for section in sections:
                JudgeScore.objects.get_or_create(
                    application=app,
                    judge=judge,
                    section=section,
                    defaults={
                        "score": Decimal(str(7 + (idx % 3))),
                        "comments": "Solid execution evidence; clear path to revenue.",
                    },
                )
                counts["scores"] += 1
        if idx == 2:
            app.return_for_info(message="Please clarify your unit economics and provide evidence of pilot revenue.")
            app.save()
            continue  # returned for info
        # idx == 3 → accepted, idx == 4 → rejected (handled in cohort confirmation)

    # Cohort confirmation (pulls accepted applications) ----------------
    open_apps = Application.objects.filter(
        programme=accelerator,
        status=Application.Status.UNDER_REVIEW,
    ).order_by("created_at")
    if open_apps.count() >= 2 and not accelerator.cohorts.exists():
        accept_apps = list(open_apps[:1])
        for app in accept_apps:
            app.accept(by_user=officer, weighted_score=Decimal("78.50"))
            app.save()
        for app in open_apps[1:]:
            app.reject(by_user=officer, weighted_score=Decimal("52.00"))
            app.save()

        cohort = Cohort.objects.create(
            programme=accelerator,
            name="C1 — Spring 2026",
            start_date=today + timedelta(days=21),
            end_date=today + timedelta(days=21 + accelerator.duration_weeks * 7),
            venue="Makerere AIH, Kampala",
        )
        counts["cohorts"] += 1
        for app in accept_apps:
            member = CohortMember.objects.create(
                cohort=cohort,
                application=app,
                entrepreneur=app.entrepreneur,
                business=app.business,
            )
            ProgressRecord.objects.get_or_create(cohort_member=member)
            counts["members"] += 1

            # Assign a mentor + schedule sessions
            if mentors:
                mentor = mentors[counts["members"] % len(mentors)]
                assignment, ma_created = MentorAssignment.objects.get_or_create(
                    cohort_member=member,
                    mentor=mentor,
                    ended_at__isnull=True,
                    defaults={"notes": "Auto-assigned by seeder"},
                )
                if ma_created:
                    counts["mentor_assignments"] += 1
                # 3 sessions: 1 completed, 1 scheduled, 1 cancelled
                MentorSession.objects.get_or_create(
                    assignment=assignment,
                    starts_at=timezone.now() - timedelta(days=7),
                    defaults={
                        "duration_minutes": 60,
                        "type": MentorSession.Type.VIRTUAL,
                        "agenda": "Kick-off — review business model canvas",
                        "status": MentorSession.Status.COMPLETED,
                        "completed_at": timezone.now() - timedelta(days=7) + timedelta(minutes=60),
                        "notes": "Productive first call, action items shared.",
                    },
                )
                MentorSession.objects.get_or_create(
                    assignment=assignment,
                    starts_at=timezone.now() + timedelta(days=7),
                    defaults={
                        "duration_minutes": 60,
                        "type": MentorSession.Type.VIRTUAL,
                        "agenda": "Financial model deep-dive",
                        "status": MentorSession.Status.SCHEDULED,
                    },
                )
                MentorSession.objects.get_or_create(
                    assignment=assignment,
                    starts_at=timezone.now() - timedelta(days=2),
                    defaults={
                        "duration_minutes": 60,
                        "type": MentorSession.Type.PHYSICAL,
                        "agenda": "On-site visit (cancelled due to weather)",
                        "status": MentorSession.Status.CANCELLED,
                        "cancellation_reason": "Travel disruption",
                    },
                )
                counts["sessions"] += 3

    # Closed-cohort archive: members + certificates --------------------
    archive = programmes["Coastal Trade Cohort 2025"]
    if not archive.cohorts.exists():
        archive_cohort = Cohort.objects.create(
            programme=archive,
            name="C0 — 2025",
            start_date=today - timedelta(days=300),
            end_date=today - timedelta(days=120),
            venue="Sokoine University AIH",
        )
        counts["cohorts"] += 1
        # Pull two verified businesses we haven't already used
        used_business_ids = set(
            CohortMember.objects.values_list("business_id", flat=True),
        )
        archive_businesses = list(
            Business.objects.filter(verification_status=Business.Status.VERIFIED)
            .exclude(pk__in=used_business_ids)[:2],
        )
        for biz in archive_businesses:
            archive_app, _ = Application.objects.get_or_create(
                programme=archive,
                business=biz,
                defaults={
                    "entrepreneur": biz.entrepreneur,
                    "business_description": f"{biz.name} historical archive.",
                    "problem_statement": "Archived programme application.",
                    "traction": "Completed in 2025.",
                    "funding_needs": "—",
                    "support_sought": "—",
                },
            )
            # Push directly through the FSM to ACCEPTED
            if archive_app.status == Application.Status.DRAFT:
                archive_app.submit()
                archive_app.save()
            if archive_app.status == Application.Status.SUBMITTED:
                archive_app.accept(by_user=officer, weighted_score=Decimal("82.00"))
                archive_app.save()
            archive_member, m_created = CohortMember.objects.get_or_create(
                cohort=archive_cohort,
                application=archive_app,
                defaults={"entrepreneur": biz.entrepreneur, "business": biz},
            )
            if m_created:
                counts["members"] += 1
                ProgressRecord.objects.create(
                    cohort_member=archive_member,
                    sessions_completed=12,
                    last_milestone_at=timezone.now() - timedelta(days=120),
                )
                # Mark complete + create certificate
                archive_member.mark_complete(manual=True, notes="Completed end of 2025 cohort.")
                archive_member.save()
                from apps.smehub.incubation.models import Certificate

                Certificate.objects.get_or_create(
                    cohort_member=archive_member,
                    defaults={"issued_by": officer},
                )
                counts["certificates"] += 1

    return counts
