"""complyform-customer-health — weekly customer health scoring.

Trigger: Weekly Cloud Scheduler (Monday 07:00 UTC).

Computes a health score per active customer based on scan recency, finding
resolution rate, and login frequency.  Writes scores to
``customers/{id}/health_scores/latest`` for the dashboard and flags at-risk
accounts (score < 40) for CS follow-up.

Contract: per-customer error isolation.
"""

from __future__ import annotations

import logging
from datetime import UTC, datetime
from typing import Any

from backend.ops._shared import cloud_function_wrapper, log_action, send_alert_email
from backend.shared.firestore import get_db

_log = logging.getLogger(__name__)

_AT_RISK_THRESHOLD = 40
_LOOKBACK_DAYS = 30


def _score_scan_recency(last_scan: str | None, now: datetime) -> float:
    """0-40 points based on days since last scan."""
    if not last_scan:
        return 0.0
    try:
        last = datetime.fromisoformat(last_scan)
    except ValueError, TypeError:
        return 0.0
    days = (now - last).total_seconds() / 86400
    if days <= 7:
        return 40.0
    if days <= 14:
        return 30.0
    if days <= 30:
        return 20.0
    if days <= 60:
        return 10.0
    return 0.0


def _score_resolution_rate(resolved: int, total: int) -> float:
    """0-40 points based on finding resolution rate."""
    if total == 0:
        return 40.0  # No findings = healthy
    rate = resolved / total
    return round(rate * 40, 1)


def _score_login_recency(last_login: str | None, now: datetime) -> float:
    """0-20 points based on days since last login."""
    if not last_login:
        return 0.0
    try:
        last = datetime.fromisoformat(last_login)
    except ValueError, TypeError:
        return 0.0
    days = (now - last).total_seconds() / 86400
    if days <= 3:
        return 20.0
    if days <= 7:
        return 15.0
    if days <= 14:
        return 10.0
    if days <= 30:
        return 5.0
    return 0.0


@cloud_function_wrapper("complyform-customer-health")
async def customer_health(request: Any) -> dict[str, Any]:
    """Compute health scores for all active customers."""
    db = get_db()
    now = datetime.now(UTC)
    stats: dict[str, int] = {
        "customers_scored": 0,
        "at_risk": 0,
    }

    query = db.collection("customers").where("status", "==", "active")
    at_risk_names: list[str] = []

    async for doc in query.stream():
        customer_id = doc.id
        try:
            data = doc.to_dict() or {}
            stats["customers_scored"] += 1

            # Gather signals
            last_scan = data.get("last_scan")
            last_login = data.get("last_login")
            findings_total = data.get("findings_total", 0)
            findings_resolved = data.get("findings_resolved", 0)

            scan_score = _score_scan_recency(last_scan, now)
            resolution_score = _score_resolution_rate(findings_resolved, findings_total)
            login_score = _score_login_recency(last_login, now)
            total_score = round(scan_score + resolution_score + login_score, 1)

            health_doc = {
                "score": total_score,
                "scan_recency": scan_score,
                "resolution_rate": resolution_score,
                "login_recency": login_score,
                "computed_at": now.isoformat(),
            }

            await (
                db.collection("customers")
                .document(customer_id)
                .collection("health_scores")
                .document("latest")
                .set(health_doc)
            )

            if total_score < _AT_RISK_THRESHOLD:
                stats["at_risk"] += 1
                org = data.get("organization", customer_id)
                at_risk_names.append(f"{org} (score: {total_score})")
                log_action(
                    customer_id,
                    "customer_at_risk",
                    score=total_score,
                )
        except Exception as exc:
            log_action(customer_id, "customer_health_error", error=str(exc))
            _log.exception("Health score error for %s", customer_id)

    if at_risk_names:
        await send_alert_email(
            subject=f"[ComplyForm] {len(at_risk_names)} at-risk customer(s)",
            body=(
                "The following customers scored below the at-risk threshold "
                f"({_AT_RISK_THRESHOLD}):\n\n"
                + "\n".join(f"  - {name}" for name in at_risk_names)
            ),
        )

    return stats


entry_point = customer_health
