from __future__ import annotations

from core.events.behavior import parse_payload
from core.events.manticore import (
    get_behavioral_events_for_range,
    get_behavioral_latest_states,
)
from core.events.shadow import (
    get_shadow_behavioral_events_for_range,
    get_shadow_behavioral_latest_states,
)
from core.models import Person, User


def _behavioral_state_from_kind(kind: str) -> tuple[str, float]:
    normalized = str(kind or "").strip().lower()
    if normalized == "presence_unavailable":
        return ("unavailable", 0.95)
    if normalized == "composing_abandoned":
        return ("fading", 0.8)
    if normalized in {
        "presence_available",
        "message_read",
        "message_delivered",
        "composing_started",
        "composing_stopped",
        "message_sent",
    }:
        return ("available", 0.75)
    return ("unknown", 0.5)


def spans_for_range(
    *,
    user: User,
    person: Person,
    start_ts: int,
    end_ts: int,
    service: str = "",
    limit: int = 200,
):
    service_filter = str(service or "").strip().lower()
    try:
        rows = get_behavioral_events_for_range(
            user_id=int(user.id),
            person_id=str(person.id),
            start_ts=int(start_ts),
            end_ts=int(end_ts),
            transport=service_filter,
        )
    except Exception:
        rows = []
    if not rows:
        rows = get_shadow_behavioral_events_for_range(
            user=user,
            person_id=str(person.id),
            start_ts=int(start_ts),
            end_ts=int(end_ts),
            transport=service_filter,
        )

    spans = []
    current = None
    for row in list(rows or []):
        transport = str(row.get("transport") or "").strip().lower()
        if service_filter and transport != service_filter:
            continue
        ts = int(row.get("ts") or 0)
        state, confidence = _behavioral_state_from_kind(str(row.get("kind") or ""))
        if current is None or str(current.get("state")) != state:
            if current is not None:
                spans.append(current)
            current = {
                "id": 0,
                "service": transport or service_filter,
                "state": state,
                "start_ts": ts,
                "end_ts": ts,
                "confidence_start": float(confidence),
                "confidence_end": float(confidence),
                "payload": {
                    "source": "manticore_behavioral",
                    "kind": str(row.get("kind") or "").strip().lower(),
                    "raw_payload": parse_payload(row.get("payload")),
                },
            }
            continue
        current["end_ts"] = max(int(current.get("end_ts") or 0), ts)
        current["confidence_end"] = float(confidence)
        payload = dict(current.get("payload") or {})
        payload["kind"] = str(row.get("kind") or "").strip().lower()
        current["payload"] = payload

    if current is not None:
        spans.append(current)
    return list(reversed(spans[: max(1, min(int(limit or 200), 500))]))


def latest_state_for_people(*, user: User, person_ids: list, service: str = "") -> dict:
    out = {}
    if not person_ids:
        return out
    service_filter = str(service or "").strip().lower()
    try:
        rows = get_behavioral_latest_states(
            user_id=int(user.id),
            person_ids=[str(value) for value in person_ids],
            transport=service_filter,
        )
    except Exception:
        rows = []
    if not rows:
        rows = get_shadow_behavioral_latest_states(
            user=user,
            person_ids=[str(value) for value in person_ids],
            transport=service_filter,
        )

    seen = set()
    for row in list(rows or []):
        person_key = str(row.get("person_id") or "").strip()
        transport = str(row.get("transport") or "").strip().lower()
        if service_filter and transport != service_filter:
            continue
        if not person_key or person_key in seen:
            continue
        seen.add(person_key)
        state, confidence = _behavioral_state_from_kind(str(row.get("kind") or ""))
        out[person_key] = {
            "state": state,
            "confidence": float(confidence),
            "service": transport or service_filter,
            "ts": int(row.get("ts") or 0),
            "source_kind": f"behavioral:{str(row.get('kind') or '').strip().lower()}",
        }
    return out
