"""SME-Hub employment snapshot services (FRSME-MEI013 ``jobs_created``).

Captures post-baseline FTE/PTE counts so the indicator builder can report
real deltas instead of leaving ``smehub-jobs-created`` as a placeholder.
"""
from __future__ import annotations

from django.db import transaction
from django.db.models import QuerySet, Subquery, OuterRef

from apps.smehub._shared.audit import AuditLog, record_audit

from apps.mel.tracking.models import EmploymentSnapshot, SMEHubTrackingRecord


@transaction.atomic
def record_employment_snapshot(
    tracking_record: SMEHubTrackingRecord,
    *,
    fte_count: int,
    pte_count: int,
    by_user,
    note: str = "",
) -> EmploymentSnapshot:
    """Persist a new employment snapshot and write an audit row.

    Officers should record snapshots quarterly or whenever they have fresh
    data from the entrepreneur — every row is appended; nothing is mutated
    in place so the time-series stays intact.
    """
    snapshot = EmploymentSnapshot.objects.create(
        tracking_record=tracking_record,
        fte_count=int(fte_count),
        pte_count=int(pte_count),
        note=(note or "")[:255],
        captured_by=by_user if by_user and by_user.is_authenticated else None,
    )
    record_audit(
        by_user,
        AuditLog.Action.UPDATE,
        snapshot,
        metadata={
            "event": "smehub_employment_snapshot_recorded",
            "tracking_record_id": tracking_record.pk,
            "fte_count": int(fte_count),
            "pte_count": int(pte_count),
        },
    )
    return snapshot


def _baseline_total(tracking_record: SMEHubTrackingRecord) -> int:
    baseline = tracking_record.baseline_snapshot
    if baseline is None and tracking_record.business_id:
        baseline = getattr(tracking_record.business, "baseline", None)
    if baseline is None:
        return 0
    return int(baseline.fte_count or 0) + int(baseline.pte_count or 0)


def compute_jobs_created(tracking_record: SMEHubTrackingRecord) -> int:
    """Latest snapshot total minus baseline total, clamped at 0.

    No snapshot recorded yet → returns 0 (no delta to report).
    Employment shrinkage → clamps at 0; we don't surface negative jobs in
    the indicator (PRD MEI013 phrases the indicator as ``jobs created``).
    """
    latest = (
        EmploymentSnapshot.objects.filter(tracking_record=tracking_record)
        .order_by("-captured_at")
        .first()
    )
    if latest is None:
        return 0
    delta = latest.total - _baseline_total(tracking_record)
    return max(0, delta)


def compute_total_jobs_created(records: QuerySet[SMEHubTrackingRecord] | None = None) -> int:
    """Aggregate ``compute_jobs_created`` across a tracking-record portfolio.

    Used by the indicator seeder + portfolio-stat strip to surface a single
    organisation-wide total. Walks records one at a time so the per-record
    clamping (negative deltas → 0) is preserved; the volumes here are
    portfolio-sized (hundreds of rows), so the loop is fine.
    """
    if records is None:
        records = SMEHubTrackingRecord.objects.all()
    return sum(compute_jobs_created(r) for r in records)
