#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations

import json
import os
import time

from services.runtime import get_logger, get_socketio
from services.state import safe_get_account, safe_iter_task_status_items


def _to_int(value, default: int = 0) -> int:
    try:
        return int(value)
    except Exception:
        return int(default)


def _payload_signature(payload: dict) -> str:
    try:
        return json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":"), default=str)
    except Exception:
        return repr(payload)


def _should_emit(
    *,
    last_sig: str | None,
    last_ts: float,
    new_sig: str,
    now_ts: float,
    min_interval: float,
    force_interval: float,
) -> bool:
    if last_sig is None:
        return True
    if (now_ts - last_ts) >= force_interval:
        return True
    if new_sig != last_sig and (now_ts - last_ts) >= min_interval:
        return True
    return False


def status_push_worker() -> None:
    """后台线程：按间隔推送排队/运行中任务状态（变更驱动+心跳兜底）。"""
    logger = get_logger()
    try:
        push_interval = float(os.environ.get("STATUS_PUSH_INTERVAL_SECONDS", "1"))
    except Exception:
        push_interval = 1.0
    push_interval = max(0.5, push_interval)

    try:
        queue_min_interval = float(os.environ.get("STATUS_PUSH_MIN_QUEUE_INTERVAL_SECONDS", str(push_interval)))
    except Exception:
        queue_min_interval = push_interval
    queue_min_interval = max(push_interval, queue_min_interval)

    try:
        progress_min_interval = float(
            os.environ.get("STATUS_PUSH_MIN_PROGRESS_INTERVAL_SECONDS", str(push_interval))
        )
    except Exception:
        progress_min_interval = push_interval
    progress_min_interval = max(push_interval, progress_min_interval)

    try:
        force_interval = float(os.environ.get("STATUS_PUSH_FORCE_INTERVAL_SECONDS", "10"))
    except Exception:
        force_interval = 10.0
    force_interval = max(push_interval, force_interval)

    socketio = get_socketio()
    from services.tasks import get_task_scheduler

    scheduler = get_task_scheduler()
    emitted_state: dict[str, dict] = {}

    while True:
        try:
            now_ts = time.time()
            queue_snapshot = scheduler.get_queue_state_snapshot()
            pending_total = int(queue_snapshot.get("pending_total", 0) or 0)
            running_total = int(queue_snapshot.get("running_total", 0) or 0)
            running_by_user = queue_snapshot.get("running_by_user") or {}
            positions = queue_snapshot.get("positions") or {}
            active_account_ids = set()

            status_items = safe_iter_task_status_items()
            for account_id, status_info in status_items:
                status = status_info.get("status")
                if status not in ("运行中", "排队中"):
                    continue
                user_id = status_info.get("user_id")
                if not user_id:
                    continue

                active_account_ids.add(str(account_id))
                account = safe_get_account(user_id, account_id)
                if not account:
                    continue

                user_id_int = _to_int(user_id)
                account_data = account.to_dict()
                pos = positions.get(account_id) or positions.get(str(account_id)) or {}
                account_data.update(
                    {
                        "queue_pending_total": pending_total,
                        "queue_running_total": running_total,
                        "queue_ahead": pos.get("queue_ahead"),
                        "queue_position": pos.get("queue_position"),
                        "queue_is_vip": pos.get("is_vip"),
                        "queue_running_user": _to_int(running_by_user.get(user_id_int, running_by_user.get(str(user_id_int), 0))),
                    }
                )

                cache_entry = emitted_state.setdefault(str(account_id), {})
                account_sig = _payload_signature(account_data)
                if _should_emit(
                    last_sig=cache_entry.get("account_sig"),
                    last_ts=float(cache_entry.get("account_ts", 0) or 0),
                    new_sig=account_sig,
                    now_ts=now_ts,
                    min_interval=queue_min_interval,
                    force_interval=force_interval,
                ):
                    socketio.emit("account_update", account_data, room=f"user_{user_id}")
                    cache_entry["account_sig"] = account_sig
                    cache_entry["account_ts"] = now_ts

                if status != "运行中":
                    continue

                progress = status_info.get("progress", {}) or {}
                progress_data = {
                    "account_id": account_id,
                    "stage": status_info.get("detail_status", ""),
                    "total_items": account.total_items,
                    "browsed_items": progress.get("items", 0),
                    "total_attachments": account.total_attachments,
                    "viewed_attachments": progress.get("attachments", 0),
                    "start_time": status_info.get("start_time", 0),
                    "elapsed_seconds": account_data.get("elapsed_seconds", 0),
                    "elapsed_display": account_data.get("elapsed_display", ""),
                    "queue_pending_total": pending_total,
                    "queue_running_total": running_total,
                    "queue_ahead": pos.get("queue_ahead"),
                    "queue_position": pos.get("queue_position"),
                    "queue_running_user": _to_int(running_by_user.get(user_id_int, running_by_user.get(str(user_id_int), 0))),
                }

                progress_sig = _payload_signature(progress_data)
                if _should_emit(
                    last_sig=cache_entry.get("progress_sig"),
                    last_ts=float(cache_entry.get("progress_ts", 0) or 0),
                    new_sig=progress_sig,
                    now_ts=now_ts,
                    min_interval=progress_min_interval,
                    force_interval=force_interval,
                ):
                    socketio.emit("task_progress", progress_data, room=f"user_{user_id}")
                    cache_entry["progress_sig"] = progress_sig
                    cache_entry["progress_ts"] = now_ts

            if emitted_state:
                stale_ids = [account_id for account_id in emitted_state.keys() if account_id not in active_account_ids]
                for account_id in stale_ids:
                    emitted_state.pop(account_id, None)

            time.sleep(push_interval)
        except Exception as e:
            logger.debug(f"状态推送出错: {e}")
            time.sleep(push_interval)
