#!/usr/bin/env python3
#
# Copyright (c) 2025 Stormux
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

"""Shared speech history buffer.

This module records the last N unique utterances spoken by Cthulhu.

Uniqueness is enforced only within the current history window. If an item
falls off the end, it may be added again later.
"""

from __future__ import annotations

from typing import Optional
import threading
from collections import deque

from . import debug

_loggerPrefix = "SpeechHistory:"

_maxHistorySize = 50
_historyItems = deque()
_historySet = set()

_lock = threading.Lock()
_pauseCount = 0
_pausedIgnoreCount = 0


def pause_capture(reason: str = "") -> None:
    """Pause capture so speech produced while paused is not recorded."""
    global _pauseCount
    with _lock:
        _pauseCount += 1
        global _pausedIgnoreCount
        _pausedIgnoreCount = 0
        debug.printMessage(
            debug.LEVEL_INFO,
            f"{_loggerPrefix} capture paused (count={_pauseCount}) reason='{reason}'",
            True,
        )


def resume_capture(reason: str = "") -> None:
    """Resume capture after a pause_capture()."""
    global _pauseCount
    with _lock:
        if _pauseCount <= 0:
            _pauseCount = 0
            debug.printMessage(
                debug.LEVEL_INFO,
                f"{_loggerPrefix} resume requested while not paused reason='{reason}'",
                True,
            )
            return

        _pauseCount -= 1
        if _pauseCount == 0:
            global _pausedIgnoreCount
            _pausedIgnoreCount = 0
        debug.printMessage(
            debug.LEVEL_INFO,
            f"{_loggerPrefix} capture resumed (count={_pauseCount}) reason='{reason}'",
            True,
        )


def is_capture_paused() -> bool:
    with _lock:
        return _pauseCount > 0


def add(text: Optional[str], source: str = "") -> bool:
    """Add text to speech history if it's not already present.

    Returns True if the item was added; False otherwise.
    """
    if text is None:
        return False

    try:
        cleanText = text.strip()
    except Exception:
        return False

    if not cleanText:
        return False

    with _lock:
        if _pauseCount > 0:
            global _pausedIgnoreCount
            _pausedIgnoreCount += 1
            if _pausedIgnoreCount in (1, 25, 50, 100):
                debug.printMessage(
                    debug.LEVEL_INFO,
                    f"{_loggerPrefix} ignoring speech while paused (ignored={_pausedIgnoreCount}) source='{source}' text='{cleanText[:80]}'",
                    True,
                )
            return False

        if cleanText in _historySet:
            debug.printMessage(
                debug.LEVEL_INFO,
                f"{_loggerPrefix} duplicate ignored source='{source}' text='{cleanText[:80]}'",
                True,
            )
            return False

        _historyItems.appendleft(cleanText)
        _historySet.add(cleanText)

        evictedText = None
        if len(_historyItems) > _maxHistorySize:
            evictedText = _historyItems.pop()
            _historySet.discard(evictedText)

        debug.printMessage(
            debug.LEVEL_INFO,
            f"{_loggerPrefix} added source='{source}' size={len(_historyItems)} text='{cleanText[:80]}'",
            True,
        )
        if evictedText:
            debug.printMessage(
                debug.LEVEL_INFO,
                f"{_loggerPrefix} evicted size={len(_historyItems)} text='{evictedText[:80]}'",
                True,
            )

        return True


def get_items() -> list[str]:
    """Return a snapshot of history items, newest-first."""
    with _lock:
        return list(_historyItems)


def remove(text: Optional[str]) -> bool:
    """Remove an item from the history (if present)."""
    if text is None:
        return False

    try:
        cleanText = text.strip()
    except Exception:
        return False

    if not cleanText:
        return False

    with _lock:
        if cleanText not in _historySet:
            debug.printMessage(
                debug.LEVEL_INFO,
                f"{_loggerPrefix} remove ignored (not found) text='{cleanText[:80]}'",
                True,
            )
            return False

        global _historyItems
        _historyItems = deque(item for item in _historyItems if item != cleanText)
        _historySet.discard(cleanText)

        debug.printMessage(
            debug.LEVEL_INFO,
            f"{_loggerPrefix} removed size={len(_historyItems)} text='{cleanText[:80]}'",
            True,
        )
        return True
