"""Debounced queue for per-thread memory updates."""

from __future__ import annotations

import threading
from dataclasses import dataclass, field
from datetime import UTC, datetime
from typing import Any

from deerflow.config.thread_memory_config import get_thread_memory_config


@dataclass
class ThreadConversationContext:
    thread_id: str
    messages: list[Any]
    timestamp: datetime = field(default_factory=lambda: datetime.now(UTC))


class ThreadMemoryUpdateQueue:
    def __init__(self):
        self._queue_by_thread: dict[str, ThreadConversationContext] = {}
        self._lock = threading.Lock()
        self._timers: dict[str, threading.Timer] = {}
        self._processing_threads: set[str] = set()

    def add(self, thread_id: str, messages: list[Any]) -> None:
        config = get_thread_memory_config()
        if not config.enabled:
            return
        with self._lock:
            self._queue_by_thread[thread_id] = ThreadConversationContext(thread_id=thread_id, messages=messages)
            self._reset_timer(thread_id)

    def _reset_timer(self, thread_id: str) -> None:
        config = get_thread_memory_config()
        timer = self._timers.get(thread_id)
        if timer is not None:
            timer.cancel()
        timer = threading.Timer(config.debounce_seconds, self._process_thread, args=(thread_id,))
        timer.daemon = True
        self._timers[thread_id] = timer
        timer.start()

    def _process_thread(self, thread_id: str) -> None:
        from deerflow.agents.memory.thread_updater import ThreadMemoryUpdater

        with self._lock:
            if thread_id in self._processing_threads:
                self._reset_timer(thread_id)
                return
            context = self._queue_by_thread.pop(thread_id, None)
            if context is None:
                self._timers.pop(thread_id, None)
                return
            self._processing_threads.add(thread_id)
            self._timers.pop(thread_id, None)

        try:
            updater = ThreadMemoryUpdater()
            updater.update_memory(context.messages, context.thread_id)
        finally:
            with self._lock:
                self._processing_threads.discard(thread_id)


_thread_queue: ThreadMemoryUpdateQueue | None = None
_lock = threading.Lock()


def get_thread_memory_queue() -> ThreadMemoryUpdateQueue:
    global _thread_queue
    with _lock:
        if _thread_queue is None:
            _thread_queue = ThreadMemoryUpdateQueue()
        return _thread_queue
