"""Session management — save, restore, and manage chat sessions."""
from __future__ import annotations

import json
import logging
import time
import uuid
from pathlib import Path
from typing import Any

log = logging.getLogger(__name__)


class Session:
    """A single chat session with history and metadata."""

    def __init__(self, session_id: str = "", name: str = "Neue Sitzung",
                 messages: list[dict] | None = None,
                 created: float = 0, updated: float = 0):
        self.id = session_id or str(uuid.uuid4())[:8]
        self.name = name
        self.messages: list[dict] = messages or []
        self.created = created or time.time()
        self.updated = updated or time.time()

    def add_message(self, role: str, content: str):
        self.messages.append({"role": role, "content": content})
        self.updated = time.time()

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "name": self.name,
            "messages": self.messages,
            "created": self.created,
            "updated": self.updated,
        }

    @classmethod
    def from_dict(cls, data: dict) -> Session:
        return cls(
            session_id=data.get("id", ""),
            name=data.get("name", "Sitzung"),
            messages=data.get("messages", []),
            created=data.get("created", 0),
            updated=data.get("updated", 0),
        )

    @property
    def message_count(self) -> int:
        return len(self.messages)

    @property
    def summary_info(self) -> dict:
        return {
            "id": self.id,
            "name": self.name,
            "message_count": self.message_count,
            "created": self.created,
            "updated": self.updated,
        }


class SessionManager:
    """Manages multiple chat sessions with persistence."""

    def __init__(self, data_dir: str | Path = "data/sessions"):
        self.data_dir = Path(data_dir)
        self.data_dir.mkdir(parents=True, exist_ok=True)
        self._sessions: dict[str, Session] = {}
        self._active_id: str = ""
        self._load_all()

    def _load_all(self):
        """Load all sessions from disk."""
        for f in self.data_dir.glob("*.json"):
            try:
                data = json.loads(f.read_text(encoding="utf-8"))
                session = Session.from_dict(data)
                self._sessions[session.id] = session
            except Exception as e:
                log.warning("Failed to load session %s: %s", f.name, e)

        # Create default session if none exist
        if not self._sessions:
            default = Session(name="Standard-Sitzung")
            self._sessions[default.id] = default
            self._active_id = default.id
            self._save(default)
        else:
            # Most recently updated session is active
            most_recent = max(self._sessions.values(), key=lambda s: s.updated)
            self._active_id = most_recent.id

    def _save(self, session: Session):
        """Persist a session to disk."""
        path = self.data_dir / f"{session.id}.json"
        path.write_text(
            json.dumps(session.to_dict(), ensure_ascii=False, indent=2),
            encoding="utf-8",
        )

    @property
    def active(self) -> Session:
        return self._sessions[self._active_id]

    @property
    def active_id(self) -> str:
        return self._active_id

    def list_sessions(self) -> list[dict]:
        """List all sessions sorted by last updated."""
        sessions = sorted(
            self._sessions.values(),
            key=lambda s: s.updated,
            reverse=True,
        )
        return [s.summary_info for s in sessions]

    def create(self, name: str = "") -> Session:
        """Create a new session and make it active."""
        session = Session(name=name or f"Sitzung {len(self._sessions) + 1}")
        self._sessions[session.id] = session
        self._active_id = session.id
        self._save(session)
        log.info("Created session: %s (%s)", session.name, session.id)
        return session

    def switch(self, session_id: str) -> Session | None:
        """Switch to an existing session."""
        if session_id in self._sessions:
            self._active_id = session_id
            return self._sessions[session_id]
        return None

    def rename(self, session_id: str, name: str) -> bool:
        if session_id in self._sessions:
            self._sessions[session_id].name = name
            self._save(self._sessions[session_id])
            return True
        return False

    def delete(self, session_id: str) -> bool:
        """Delete a session. Cannot delete last session."""
        if session_id not in self._sessions or len(self._sessions) <= 1:
            return False
        del self._sessions[session_id]
        path = self.data_dir / f"{session_id}.json"
        path.unlink(missing_ok=True)
        if self._active_id == session_id:
            self._active_id = next(iter(self._sessions))
        return True

    def add_message(self, role: str, content: str):
        """Add a message to the active session."""
        self.active.add_message(role, content)
        self._save(self.active)

    def add_message_to(self, session_id: str, role: str, content: str):
        """Add a message to a specific session without changing the active session."""
        if session_id in self._sessions:
            self._sessions[session_id].add_message(role, content)
            self._save(self._sessions[session_id])

    def get_or_create(self, session_id: str, name: str) -> Session:
        """Return an existing session by *session_id* or create a new one with that id.

        Unlike :meth:`create`, this does **not** change the active session.
        Useful for external gateways (e.g. Telegram) that manage their own session
        lifetime independently of the dashboard.
        """
        if session_id in self._sessions:
            return self._sessions[session_id]
        session = Session(session_id=session_id, name=name)
        self._sessions[session_id] = session
        self._save(session)
        log.info("Created external session: %s (%s)", name, session_id)
        return session

    def get_history(self, session_id: str = "") -> list[dict]:
        """Get message history for a session."""
        sid = session_id or self._active_id
        if sid in self._sessions:
            return self._sessions[sid].messages
        return []

    def save_active(self):
        """Explicitly save the active session."""
        self._save(self.active)
