from __future__ import annotations

from django.core.management.base import BaseCommand

from core.events.ledger import append_event_sync
from core.models import Message
from core.presence.inference import now_ms


class Command(BaseCommand):
    help = (
        "Replay behavioral event ledger rows from persisted message, receipt, "
        "and reaction history."
    )

    def add_arguments(self, parser):
        parser.add_argument("--days", type=int, default=90)
        parser.add_argument("--limit", type=int, default=20000)
        parser.add_argument("--service", default="")
        parser.add_argument("--user-id", default="")
        parser.add_argument("--dry-run", action="store_true", default=False)
        parser.add_argument("--no-reset", action="store_true", default=False)

    def _iter_messages(self, *, days: int, limit: int, service: str, user_id: str):
        cutoff_ts = now_ms() - (max(1, int(days)) * 24 * 60 * 60 * 1000)
        qs = Message.objects.filter(ts__gte=cutoff_ts).select_related(
            "user", "session", "session__identifier", "session__identifier__person"
        )
        if service:
            qs = qs.filter(source_service=str(service).strip().lower())
        if user_id:
            qs = qs.filter(user_id=str(user_id).strip())
        return qs.order_by("ts")[: max(1, int(limit))]

    def handle(self, *args, **options):
        days = max(1, int(options.get("days") or 90))
        limit = max(1, int(options.get("limit") or 20000))
        service_filter = str(options.get("service") or "").strip().lower()
        user_filter = str(options.get("user_id") or "").strip()
        dry_run = bool(options.get("dry_run"))

        messages = list(
            self._iter_messages(
                days=days,
                limit=limit,
                service=service_filter,
                user_id=user_filter,
            )
        )
        indexed = 0

        for msg in messages:
            session = getattr(msg, "session", None)
            identifier = getattr(session, "identifier", None)
            person = getattr(identifier, "person", None)
            user = getattr(msg, "user", None)
            if not session or not identifier or not person or not user:
                continue

            service = (
                str(getattr(msg, "source_service", "") or identifier.service or "")
                .strip()
                .lower()
            )
            if not service:
                continue

            author = str(getattr(msg, "custom_author", "") or "").strip().upper()
            outgoing = author in {"USER", "BOT"}
            message_id = str(
                getattr(msg, "source_message_id", "") or f"django-message-{msg.id}"
            ).strip()

            if not dry_run:
                append_event_sync(
                    user=user,
                    session=session,
                    ts=int(getattr(msg, "ts", 0) or 0),
                    event_type="message_created",
                    direction="out" if outgoing else "in",
                    actor_identifier=str(
                        getattr(msg, "sender_uuid", "") or identifier.identifier or ""
                    ),
                    origin_transport=service,
                    origin_message_id=message_id,
                    origin_chat_id=str(getattr(msg, "source_chat_id", "") or ""),
                    payload={
                        "origin": "recalculate_contact_availability",
                        "message_id": str(msg.id),
                        "text": str(getattr(msg, "text", "") or ""),
                        "outgoing": outgoing,
                    },
                )
            indexed += 1

            read_ts = int(getattr(msg, "read_ts", 0) or 0)
            if read_ts > 0:
                if not dry_run:
                    append_event_sync(
                        user=user,
                        session=session,
                        ts=read_ts,
                        event_type="read_receipt",
                        direction="system",
                        actor_identifier=str(
                            getattr(msg, "read_by_identifier", "")
                            or identifier.identifier
                        ),
                        origin_transport=service,
                        origin_message_id=message_id,
                        origin_chat_id=str(getattr(msg, "source_chat_id", "") or ""),
                        payload={
                            "origin": "recalculate_contact_availability",
                            "message_id": str(msg.id),
                            "message_ts": int(getattr(msg, "ts", 0) or 0),
                            "read_by": str(
                                getattr(msg, "read_by_identifier", "") or ""
                            ).strip(),
                        },
                    )
                indexed += 1

            reactions = list(
                (getattr(msg, "receipt_payload", {}) or {}).get("reactions") or []
            )
            for reaction in reactions:
                item = dict(reaction or {})
                if bool(item.get("removed")):
                    continue
                reaction_ts = int(item.get("updated_at") or 0)
                if reaction_ts <= 0:
                    continue
                if not dry_run:
                    append_event_sync(
                        user=user,
                        session=session,
                        ts=reaction_ts,
                        event_type="presence_available",
                        direction="system",
                        actor_identifier=str(item.get("actor") or ""),
                        origin_transport=service,
                        origin_message_id=message_id,
                        origin_chat_id=str(getattr(msg, "source_chat_id", "") or ""),
                        payload={
                            "origin": "recalculate_contact_availability",
                            "message_id": str(msg.id),
                            "inferred_from": "reaction",
                            "emoji": str(item.get("emoji") or ""),
                            "source_service": str(item.get("source_service") or service),
                        },
                    )
                indexed += 1

        self.stdout.write(
            self.style.SUCCESS(
                "recalculate_contact_availability complete "
                f"messages_scanned={len(messages)} indexed={indexed} "
                f"dry_run={dry_run} no_reset={bool(options.get('no_reset'))} "
                f"days={days} limit={limit}"
            )
        )
