"""Event sink for persistence and external handlers."""

from __future__ import annotations

import json
import logging
import threading
import time
from concurrent.futures import TimeoutError as FutureTimeout
from typing import Any


class EventSink:
    """Handles event persistence to RAM/disk and optional external handlers."""

    def __init__(self, agent):
        self._agent = agent

    def register_to_auto_file(self, event_type: str, data: Any):
        """Writes to disk record by record if enabled."""
        agent = self._agent
        if not agent.auto_persist:
            return
        if hasattr(agent, "_sanitize_event_data"):
            data = agent._sanitize_event_data(event_type, data)
        with agent.lock:
            agent.record_counter += 1
            if agent.record_counter > agent.max_records_per_file:
                agent.log_version += 1
                agent.current_log_file = f"auto_log_{agent.name}_v{agent.log_version}.json"
                agent.record_counter = 1

            record = {"ts": time.ctime(), "type": event_type, "data": data}
            try:
                with open(agent.current_log_file, "a") as f:
                    f.write(json.dumps(record) + "\n")
            except Exception as e:
                logging.error(f"Error in automatic persistence: {e}")

    def dispatch_event(self, event_type: str, data: Any):
        """Sends event to RAM, Disk and External Handler."""
        agent = self._agent
        if hasattr(agent, "_sanitize_event_data"):
            data = agent._sanitize_event_data(event_type, data)
        with agent.lock:
            if event_type == "SUCCESS":
                agent.outbox.append(data)
            else:
                agent.incident_log.append(data)

        # Save to rotating log
        self.register_to_auto_file(event_type, data)

        # Execute External Handler (in separate thread to avoid blocking)
        if agent.external_handler:
            try:
                timeout_seconds = getattr(agent, "handler_timeout_seconds", None)

                def _run_handler():
                    agent.external_handler(event_type, data)

                if agent.executor:
                    future = agent.executor.submit(_run_handler)

                    if timeout_seconds:
                        def _watch_future():
                            try:
                                future.result(timeout=timeout_seconds)
                            except FutureTimeout:
                                logging.warning(
                                    "External handler timeout after %.2fs", timeout_seconds
                                )
                        threading.Thread(target=_watch_future, daemon=True).start()
                else:
                    thread = threading.Thread(target=_run_handler, daemon=True)
                    thread.start()

                    if timeout_seconds:
                        def _watch_thread():
                            thread.join(timeout=timeout_seconds)
                            if thread.is_alive():
                                logging.warning(
                                    "External handler timeout after %.2fs", timeout_seconds
                                )
                        threading.Thread(target=_watch_thread, daemon=True).start()
            except Exception as e:
                logging.error(f"Error in external handler: {e}")
