import threading
from datetime import datetime

from flask import Flask

from backend.services.agent_assets import compute_indexing_status
from backend.utils.logging_utils import get_logger

logger = get_logger(__name__)

_monitor_event = threading.Event()


def wake_monitor():
    """
    Call this whenever you’ve just kicked off (or cancelled) one
    or more indexing jobs, to wake the background thread.
    """
    _monitor_event.set()


def _monitor_loop(app: Flask, interval: int):
    with app.app_context():
        while True:
            # 1- Block until someone calls wake_monitor()
            _monitor_event.wait()
            _monitor_event.clear()
            logger.info("Indexing monitor woke up")
            # 2- Enter polling loop
            while True:
                try:
                    from backend.database.user_store_protocol import IUserStore

                    store: IUserStore = app.config["STORE"]
                    now = datetime.utcnow().isoformat()

                    # Gather all agents with in-flight jobs
                    from backend.config import is_answers_mode_on

                    agents = []
                    if not is_answers_mode_on():
                        agents = store.get_all_agents(all_users=True)
                    active_agents = [
                        a
                        for a in agents
                        if (idx := a.indexing)
                        and (idx.get("jobId") or idx.get("scenarioRuns"))
                        and idx.get("status") in ("pending", "running")
                    ]
                    if not active_agents:
                        logger.info("No active indexing jobs – sleeping")
                        break  # no more jobs → go back to wait()

                    # For each active job, fetch live status
                    for agent in active_agents:
                        idx = agent.indexing
                        aid = agent.id
                        logger.debug("Checking job status for agent %s", aid)
                        job_id = idx.get("jobId")
                        scenario_runs = idx.get("scenarioRuns") or []
                        live = compute_indexing_status(aid, job_id, scenario_runs)
                        if live and live.get("status") != idx["status"]:
                            # Merge in new status + timestamp
                            updated = {**idx, **live, "updatedAt": now}
                            payload = {"indexing": updated}

                            # On success → mark docs active, drop deletePending
                            if updated["status"] == "success":
                                docs = agent.documents or []
                                next_docs = []
                                for d in docs:
                                    if isinstance(d, dict) and d.get("deletePending"):
                                        continue
                                    if isinstance(d, str):
                                        next_docs.append({"name": d, "active": True})
                                    elif isinstance(d, dict):
                                        next_docs.append({**d, "active": True})
                                    else:
                                        next_docs.append(d)
                                payload["documents"] = next_docs
                            store.update_agent(agent.id, payload, bypass_user=True)
                except Exception:
                    app.logger.exception("Indexing monitor encountered an exception")

                _monitor_event.wait(interval)
                _monitor_event.clear()


def start_monitor(app: Flask, interval: int = 60):
    """
    Kick off the daemon thread.  Call once (in setup_app).
    """
    thread = threading.Thread(
        target=_monitor_loop,
        args=(app, interval),
        daemon=True,
        name="IndexingMonitor",
    )
    thread.start()
