"""Seed SME-Hub linkage (SP3a) demo data.

Idempotent. Builds on SP1 onboarding seeder (entrepreneurs + verified
businesses must exist).

Produces approximately:
* 30 partner directory entries (mix of pending / verified)
* 20 service provider entries
* 18 connection requests in mixed states (pending / accepted / declined)
* 5 MoUs (3 draft, 2 formalised) with at least one amendment chain
* 12 advisory sessions across statuses
* 4 organisation recommendations
* Recommendation snapshots for any verified entrepreneur in the dataset
"""
from __future__ import annotations

import logging
import random
from datetime import timedelta

from django.contrib.auth import get_user_model
from django.contrib.auth.hashers import make_password
from django.contrib.contenttypes.models import ContentType
from django.core.files.base import ContentFile
from django.db import transaction
from django.utils import timezone

from apps.core.countries import to_country_name
from apps.core.permissions.roles import UserRole
from apps.smehub.linkage.ai_matchmaking import refresh_recommendations
from apps.smehub.linkage.models import (
    AdvisorySession,
    Connection,
    ConnectionRequest,
    MoU,
    MoUComment,
    MoUVersion,
    OrganisationRecommendation,
    PartnerDirectoryEntry,
    ServiceProviderEntry,
)
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


_PARTNERS = [
    ("Africa Agribusiness Foundation", "ngo", ["Agriculture", "Agribusiness"], ["KE", "UG", "TZ"]),
    ("AgriCorp Holdings", "corporate", ["Agribusiness", "Trade"], ["KE"]),
    ("Equator Seed Co.", "corporate", ["Agriculture"], ["UG", "RW"]),
    ("Greenfields Ventures", "corporate", ["Agribusiness", "FinTech"], ["KE", "ET"]),
    ("RUFORUM Member Bank", "corporate", ["FinTech"], ["UG"]),
    ("EastAfrica Health Trust", "ngo", ["Health"], ["KE", "TZ", "UG"]),
    ("Lake Victoria Fisheries Co-op", "cooperative", ["Aquaculture"], ["KE", "UG", "TZ"]),
    ("Sahel Agritech NGO", "ngo", ["Agriculture", "Energy"], ["NE", "ML", "BF"]),
    ("Nile Basin Authority", "government", ["Water"], ["UG", "EG", "SD"]),
    ("Cape Innovation Hub", "university", ["Tech", "Education"], ["ZA"]),
    ("Bayelsa State MSME Office", "government", ["Manufacturing"], ["NG"]),
    ("West Africa Energy Foundation", "foundation", ["Energy"], ["GH", "NG"]),
    ("Coffee Cooperative Union", "cooperative", ["Agriculture"], ["ET", "RW"]),
    ("Agro-Ventures International", "corporate", ["Agribusiness"], ["ZA", "NG"]),
    ("Pan-African Climate Network", "ngo", ["Energy", "Agriculture"], ["KE", "ZA", "ZW"]),
    ("Hubs for Africa Coalition", "ngo", ["Tech", "Education"], ["KE", "GH", "RW"]),
    ("Kigali Institute of Tech", "university", ["Tech"], ["RW"]),
    ("DigitalAg Africa", "corporate", ["Tech", "Agribusiness"], ["KE", "UG"]),
    ("Senegal Food Trust", "ngo", ["Agriculture"], ["SN"]),
    ("Maputo Trade Authority", "government", ["Trade"], ["MZ"]),
    ("Mara Sustainable Tourism", "corporate", ["Tourism"], ["KE", "TZ"]),
    ("Cotonou Industrial Park", "government", ["Manufacturing"], ["BJ"]),
    ("Pastoral Livestock Initiative", "ngo", ["Livestock"], ["KE", "ET", "UG"]),
    ("FinTech Coalition for SMEs", "ngo", ["FinTech"], ["NG", "KE"]),
    ("Ethiopia Edu-Innovation", "university", ["Education"], ["ET"]),
    ("Ouagadougou Logistics Group", "corporate", ["Transport"], ["BF"]),
    ("ZAMSCALE Agribusiness", "corporate", ["Agribusiness"], ["ZM"]),
    ("Botswana Mining Cooperative", "cooperative", ["Mining"], ["BW"]),
    ("RUFORUM Foundation", "foundation", ["Education", "Agriculture"], ["UG", "KE", "ZA"]),
    ("Sudan Solar Energy Trust", "foundation", ["Energy"], ["SD", "SS"]),
]

_PROVIDERS = [
    ("Kampala Legal Partners", "corporate", ["legal"], ["UG"], ["Agriculture", "Trade"]),
    ("Equity Tax & Audit", "corporate", ["finance"], ["KE"], ["FinTech", "Manufacturing"]),
    ("BrandKraft Designs", "corporate", ["packaging", "marketing"], ["KE", "UG"], ["Agriculture", "Manufacturing"]),
    ("Halal Certification Africa", "ngo", ["certification"], ["KE", "TZ"], ["Agribusiness"]),
    ("Quality Lab Africa", "corporate", ["qa", "certification"], ["ZA", "KE"], ["Health", "Agribusiness"]),
    ("Patent Office Consulting", "corporate", ["ip", "legal"], ["NG", "GH"], ["Tech", "FinTech"]),
    ("CapacityHub Trainers", "ngo", ["training"], ["UG", "KE"], ["Education", "Agribusiness"]),
    ("Cold Chain Logistics", "corporate", ["logistics", "packaging"], ["KE"], ["Agribusiness"]),
    ("FarmTech Studios", "corporate", ["tech"], ["NG", "KE"], ["Agriculture", "Tech"]),
    ("Lagos Marketing Lab", "corporate", ["marketing"], ["NG"], ["FinTech", "Tech"]),
    ("African Quality Assurance", "ngo", ["qa"], ["KE", "ZA"], ["Manufacturing", "Health"]),
    ("Compliance Africa Trust", "ngo", ["legal", "certification"], ["KE", "UG", "TZ"], ["Agribusiness"]),
    ("Pan-African Audit Group", "corporate", ["finance"], ["NG", "GH", "KE"], ["FinTech", "Trade"]),
    ("Eco-Brand Studio", "corporate", ["packaging", "marketing"], ["KE", "RW"], ["Agriculture"]),
    ("Innovation Patents Africa", "ngo", ["ip"], ["KE", "ZA"], ["Tech"]),
    ("AgriLogistics Hub", "corporate", ["logistics"], ["UG", "TZ"], ["Agriculture"]),
    ("Tech Mentor Collective", "ngo", ["training", "tech"], ["KE", "ZA"], ["Tech"]),
    ("AfricaSecure Cybersec", "corporate", ["tech"], ["ZA"], ["FinTech", "Tech"]),
    ("DigitalPay Solutions", "corporate", ["tech", "finance"], ["KE", "UG"], ["FinTech"]),
    ("Crop Health Diagnostics", "corporate", ["qa"], ["UG", "KE"], ["Agriculture"]),
]


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


def _ensure_admin() -> User:
    return _ensure_user(
        "smehub-admin@ruforum.org",
        first="Sara",
        last="Admin",
        role=UserRole.SME_ADMIN,
    )


def _seed_partners(admin: User) -> int:
    created = 0
    for idx, (name, org_type, sectors, geo) in enumerate(_PARTNERS):
        manager = _ensure_user(
            f"partner{idx + 1}@ruforum.org",
            first=name.split(" ")[0],
            last="Lead",
            role=UserRole.PARTNER,
        )
        entry, was_created = PartnerDirectoryEntry.objects.get_or_create(
            organisation_name=name,
            defaults={
                "org_type": org_type,
                "sector_focus": sectors,
                "geographic_coverage": [to_country_name(c) for c in geo],
                "contact_email": f"contact-{idx + 1}@partners.example",
                "description": f"{name} works across {', '.join(sectors)}.",
                "areas_of_interest": "Open to RUFORUM-supported entrepreneurs in our focus areas.",
                "managed_by": manager,
            },
        )
        if was_created:
            created += 1
        # Verify ~85% of partners
        if idx % 7 != 0 and entry.verification_status == PartnerDirectoryEntry.Status.PENDING:
            entry.verify(by_user=admin)
            entry.save()
    return created


def _seed_providers(admin: User) -> int:
    created = 0
    for idx, (name, org_type, services, geo, sectors) in enumerate(_PROVIDERS):
        manager = _ensure_user(
            f"provider{idx + 1}@ruforum.org",
            first=name.split(" ")[0],
            last="Pro",
            role=UserRole.SERVICE_PROVIDER,
        )
        entry, was_created = ServiceProviderEntry.objects.get_or_create(
            organisation_name=name,
            defaults={
                "org_type": org_type,
                "service_offerings": services,
                "sector_focus": sectors,
                "geographic_coverage": [to_country_name(c) for c in geo],
                "contact_email": f"hi-{idx + 1}@providers.example",
                "description": f"{name} delivers {' and '.join(services)} services.",
                "areas_of_interest": "Available for short-form advisory engagements.",
                "managed_by": manager,
            },
        )
        if was_created:
            created += 1
        if idx % 9 != 0 and entry.verification_status == ServiceProviderEntry.Status.PENDING:
            entry.verify(by_user=admin)
            entry.save()
    return created


def _seed_connections(admin: User) -> dict:
    profiles = list(
        EntrepreneurProfile.objects.filter(
            verification_status=EntrepreneurProfile.Status.VERIFIED,
        )[:6]
    )
    partners = list(
        PartnerDirectoryEntry.objects.filter(
            verification_status=PartnerDirectoryEntry.Status.VERIFIED,
        )[:6]
    )
    providers = list(
        ServiceProviderEntry.objects.filter(
            verification_status=ServiceProviderEntry.Status.VERIFIED,
        )[:6]
    )
    if not profiles or not partners:
        return {"requests": 0, "connections": 0}

    partner_ct = ContentType.objects.get_for_model(PartnerDirectoryEntry)
    provider_ct = ContentType.objects.get_for_model(ServiceProviderEntry)

    request_count = 0
    connection_count = 0
    rng = random.Random(42)

    pairs = []
    for profile in profiles:
        for partner in partners[: 3]:
            pairs.append((profile, partner, partner_ct))
        for provider in providers[: 2]:
            pairs.append((profile, provider, provider_ct))

    rng.shuffle(pairs)
    pairs = pairs[:18]

    for index, (profile, target, ct) in enumerate(pairs):
        cr, was_created = ConnectionRequest.objects.get_or_create(
            entrepreneur=profile,
            target_content_type=ct,
            target_object_id=str(target.pk),
            defaults={
                "message": f"Hi {target.organisation_name}, our work overlaps and we'd love to talk.",
            },
        )
        if not was_created:
            continue
        request_count += 1
        # Distribute outcomes: 60% accepted, 25% declined, 15% pending
        outcome = index % 7
        if outcome in (0, 1, 2, 3):
            cr.accept(by_user=target.managed_by or admin)
            cr.save()
            Connection.objects.get_or_create(
                request=cr,
                defaults={
                    "entrepreneur": profile,
                    "target_content_type": ct,
                    "target_object_id": str(target.pk),
                },
            )
            connection_count += 1
        elif outcome in (4, 5):
            cr.decline(by_user=target.managed_by or admin, reason="Not aligned this quarter.")
            cr.save()
        # else leave pending
    return {"requests": request_count, "connections": connection_count}


def _seed_mous(admin: User) -> int:
    connections = list(Connection.objects.all()[:5])
    if not connections:
        return 0
    created = 0
    for idx, connection in enumerate(connections):
        title = f"MoU between {connection.entrepreneur.user.email.split('@')[0]} and {connection.target}"
        mou, was_created = MoU.objects.get_or_create(
            connection=connection,
            title=title,
            defaults={
                "summary": "Collaboration on market access, supply chain, and capacity building.",
                "draft_file": ContentFile(
                    b"% DRAFT MoU placeholder %\nGenerated by SME-Hub seeder.\n",
                    name=f"mou-draft-{connection.pk}.txt",
                ),
                "created_by": connection.entrepreneur.user,
            },
        )
        if was_created:
            created += 1
            MoUVersion.objects.create(
                mou=mou,
                version_number=1,
                title=mou.title,
                summary=mou.summary,
                file=mou.draft_file,
                status_at_version=mou.status,
                notes="Initial draft.",
                created_by=connection.entrepreneur.user,
            )
            MoUComment.objects.get_or_create(
                mou=mou,
                author=admin,
                body="Looks good — please clarify the IP clause in section 4.",
            )
        # Formalise the first two
        if idx < 2 and mou.status in (MoU.Status.DRAFT, MoU.Status.UNDER_REVIEW):
            mou.signed_file = ContentFile(
                b"% SIGNED MoU placeholder %\nFormalised via SME-Hub seeder.\n",
                name=f"mou-signed-{connection.pk}.txt",
            )
            mou.formalise(by_user=admin)
            mou.save()
            MoUVersion.objects.create(
                mou=mou,
                version_number=2,
                title=mou.title,
                summary=mou.summary,
                file=mou.signed_file,
                status_at_version=mou.status,
                notes="Formalised by admin.",
                created_by=admin,
            )
        # First formalised MoU also gets an amendment chain
        if idx == 0 and mou.status == MoU.Status.FORMALISED:
            child_title = f"{mou.title} — Addendum"
            child, child_created = MoU.objects.get_or_create(
                connection=connection,
                title=child_title,
                defaults={
                    "summary": "Annual scope refresh.",
                    "parent_mou": mou,
                    "created_by": connection.entrepreneur.user,
                },
            )
            if child_created:
                MoUVersion.objects.create(
                    mou=child,
                    version_number=1,
                    title=child.title,
                    summary=child.summary,
                    status_at_version=child.status,
                    notes="Amendment draft.",
                    created_by=connection.entrepreneur.user,
                )
                if mou.status != MoU.Status.AMENDED:
                    mou.mark_amended()
                    mou.save()
    return created


def _seed_advisory_sessions(admin: User) -> int:
    profiles = list(
        EntrepreneurProfile.objects.filter(
            verification_status=EntrepreneurProfile.Status.VERIFIED,
        )[:4]
    )
    providers = list(
        ServiceProviderEntry.objects.filter(
            verification_status=ServiceProviderEntry.Status.VERIFIED,
        )[:4]
    )
    if not profiles or not providers:
        return 0
    created = 0
    now = timezone.now()
    schedules = [
        (now + timedelta(days=2), "scheduled"),
        (now + timedelta(days=7), "scheduled"),
        (now + timedelta(days=14), "scheduled"),
        (now - timedelta(days=2), "completed"),
        (now - timedelta(days=8), "completed"),
        (now - timedelta(days=15), "completed"),
        (now - timedelta(days=22), "cancelled"),
        (now - timedelta(days=29), "completed"),
        (now + timedelta(days=21), "scheduled"),
        (now - timedelta(days=4), "scheduled"),
        (now - timedelta(days=11), "completed"),
        (now + timedelta(days=30), "scheduled"),
    ]
    for index, (when, target_status) in enumerate(schedules):
        profile = profiles[index % len(profiles)]
        provider = providers[index % len(providers)]
        session, was_created = AdvisorySession.objects.get_or_create(
            entrepreneur=profile,
            service_provider=provider,
            starts_at=when,
            defaults={
                "duration_minutes": 60 + (index % 3) * 30,
                "agenda": "Quarterly advisory checkpoint.",
                "type": AdvisorySession.Type.VIRTUAL,
                "status": target_status if target_status != "completed" else AdvisorySession.Status.SCHEDULED,
            },
        )
        if was_created:
            created += 1
        if target_status == "completed" and session.status != AdvisorySession.Status.COMPLETED:
            session.status = AdvisorySession.Status.COMPLETED
            session.completed_at = when + timedelta(hours=1)
            session.notes = "Action items captured."
            session.save(update_fields=["status", "completed_at", "notes"])
        elif target_status == "cancelled" and session.status != AdvisorySession.Status.CANCELLED:
            session.status = AdvisorySession.Status.CANCELLED
            session.cancellation_reason = "Provider unavailable — rescheduled offline."
            session.save(update_fields=["status", "cancellation_reason"])
    return created


def _seed_recommendations() -> int:
    rec_seed = [
        ("partner", "Northern Africa Trade Hub", "alumna@example.com"),
        ("service_provider", "Hands-on Compliance Trainers", "alumna@example.com"),
        ("partner", "Greenwave Foundation", "alumnus@example.com"),
        ("buyer", "AfriCold Chain Buyers", "alumnus@example.com"),
    ]
    created = 0
    for kind, name, email in rec_seed:
        suggester = User.objects.filter(email__icontains=email.split("@")[0]).first()
        rec, was_created = OrganisationRecommendation.objects.get_or_create(
            organisation_name=name,
            defaults={
                "kind": kind,
                "rationale": f"Spotted {name} would fit the directory.",
                "sector_focus": ["Agriculture"],
                "geographic_coverage": [to_country_name(c) for c in ["KE", "UG"]],
                "suggested_by": suggester,
            },
        )
        if was_created:
            created += 1
    return created


def _refresh_snapshots() -> int:
    n = 0
    for profile in EntrepreneurProfile.objects.filter(
        verification_status=EntrepreneurProfile.Status.VERIFIED,
    ):
        try:
            refresh_recommendations(profile, trigger="seeder")
            n += 1
        except Exception as exc:  # noqa: BLE001
            logger.warning("snapshot refresh failed for %s: %s", profile.pk, exc)
    return n


@transaction.atomic
def seed() -> dict:
    admin = _ensure_admin()
    partners = _seed_partners(admin)
    providers = _seed_providers(admin)
    connections = _seed_connections(admin)
    mous = _seed_mous(admin)
    advisory = _seed_advisory_sessions(admin)
    recs = _seed_recommendations()
    snapshots = _refresh_snapshots()
    return {
        "partners": partners,
        "providers": providers,
        "connection_requests": connections["requests"],
        "connections": connections["connections"],
        "mous": mous,
        "advisory_sessions": advisory,
        "recommendations": recs,
        "snapshots_refreshed": snapshots,
    }
