"""
Хранилище сессий в памяти с автоочисткой по TTL.

Использование:
    sid = create_session()
    add_file(sid, filename, content_bytes)
    files = get_files(sid)
    store_result(sid, zip_bytes)
    zip_data = get_result(sid)
    cleanup(sid)
"""

import uuid
import threading
import time
from typing import Dict, List, Tuple, Optional

# ═══════════════════════════════════════════════════════════════════════════
# Данные сессии
# ═══════════════════════════════════════════════════════════════════════════

TTL_SECONDS = 30 * 60  # 30 минут

_sessions: Dict[str, dict] = {}
_lock = threading.Lock()


def _start_timer(sid: str):
    """Запустить таймер автоочистки сессии через TTL."""

    def _clean():
        with _lock:
            _sessions.pop(sid, None)

    timer = threading.Timer(TTL_SECONDS, _clean)
    timer.daemon = True
    timer.start()
    return timer


# ═══════════════════════════════════════════════════════════════════════════
# API
# ═══════════════════════════════════════════════════════════════════════════

def create_session() -> str:
    """Создать новую сессию.

    Returns:
        Уникальный идентификатор сессии (UUID).
    """
    sid = uuid.uuid4().hex[:12]
    with _lock:
        _sessions[sid] = {
            "files": [],
            "result": None,
            "timer": _start_timer(sid),
        }
    return sid


def add_file(sid: str, filename: str, content: bytes) -> bool:
    """Добавить файл в сессию.

    Args:
        sid: Идентификатор сессии
        filename: Имя файла
        content: Бинарное содержимое

    Returns:
        True если сессия существует, False если нет.
    """
    with _lock:
        s = _sessions.get(sid)
        if not s:
            return False
        s["files"].append((filename, content))
        return True


def get_files(sid: str) -> Optional[List[Tuple[str, bytes]]]:
    """Получить все файлы сессии.

    Args:
        sid: Идентификатор сессии

    Returns:
        [(filename, content), ...] или None если сессия не найдена.
    """
    with _lock:
        s = _sessions.get(sid)
        return list(s["files"]) if s else None


def file_count(sid: str) -> int:
    """Количество файлов в сессии."""
    with _lock:
        s = _sessions.get(sid)
        return len(s["files"]) if s else 0


def store_result(sid: str, zip_data: bytes) -> bool:
    """Сохранить результат обработки.

    Args:
        sid: Идентификатор сессии
        zip_data: ZIP-архив с результатом

    Returns:
        True если сессия существует, False если нет.
    """
    with _lock:
        s = _sessions.get(sid)
        if not s:
            return False
        s["result"] = zip_data
        return True


def get_result(sid: str) -> Optional[bytes]:
    """Получить результат обработки.

    Args:
        sid: Идентификатор сессии

    Returns:
        ZIP-архив или None если сессия не найдена/результат не готов.
    """
    with _lock:
        s = _sessions.get(sid)
        return s["result"] if s else None


def cleanup(sid: str):
    """Удалить сессию."""
    with _lock:
        s = _sessions.pop(sid, None)
        if s and s.get("timer"):
            s["timer"].cancel()


def store_csv(sid: str, csv_str: str) -> bool:
    """Сохранить CSV с таблицей замен.

    Args:
        sid: Идентификатор сессии
        csv_str: Строка CSV

    Returns:
        True если сессия существует, False если нет.
    """
    with _lock:
        s = _sessions.get(sid)
        if not s:
            return False
        s["csv"] = csv_str
        return True


def get_csv(sid: str) -> Optional[str]:
    """Получить CSV с таблицей замен.

    Args:
        sid: Идентификатор сессии

    Returns:
        Строка CSV или None если нет.
    """
    with _lock:
        s = _sessions.get(sid)
        return s.get("csv") if s else None
