"""
Player Journal — lightweight per-player memory files.

Each player gets a small text file (1-5 lines) that the model reads before
responding and updates after meaningful interactions. The model has free reign
to overwrite these files to keep them short and contextually relevant.

Files stored at: <config.journal_path>/<player_name>.txt

For God mode: includes sentiment, relationship history, divine interactions.
For Sudo mode: includes past builds, preferences, saved locations, skill level.

Usage:
    from agent.tools.player_journal import read_journal, write_journal, format_journal_context

    # Read before responding
    context = read_journal(config, player)

    # Update after interaction
    write_journal(config, player, new_content)

    # Inject into system prompt
    prompt += format_journal_context(config, player)
"""

import os
import threading
from pathlib import Path
from typing import Optional

_lock = threading.Lock()


def _journal_dir(config: dict) -> Path:
    return Path(config.get("journal_path", config.get("memory_path", "/tmp").replace("aigod_memory.json", "journals")))


def _journal_path(config: dict, player: str) -> Path:
    d = _journal_dir(config)
    # Sanitize player name
    safe = "".join(c for c in player if c.isalnum() or c in "_-").strip()
    if not safe:
        safe = "unknown"
    return d / f"{safe}.txt"


def read_journal(config: dict, player: str) -> str:
    """Read a player's journal. Returns empty string if none exists."""
    path = _journal_path(config, player)
    try:
        with open(path) as f:
            return f.read().strip()
    except FileNotFoundError:
        return ""


def write_journal(config: dict, player: str, content: str):
    """Overwrite a player's journal. Aim for 1-5 lines but longer is fine for
    players with complex history. Max 10 lines — if longer, the model should
    condense older entries to make room for new context."""
    path = _journal_path(config, player)
    d = _journal_dir(config)

    with _lock:
        d.mkdir(parents=True, exist_ok=True)
        lines = [l.strip() for l in content.strip().split("\n") if l.strip()]
        if len(lines) > 10:
            lines = lines[-10:]
        with open(path, "w") as f:
            f.write("\n".join(lines) + "\n")


def append_journal(config: dict, player: str, line: str):
    """Add a line to a player's journal, keeping it under 5 lines.
    Oldest line gets dropped if at capacity."""
    current = read_journal(config, player)
    lines = [l for l in current.split("\n") if l.strip()]
    lines.append(line.strip())
    if len(lines) > 5:
        lines = lines[-5:]
    write_journal(config, player, "\n".join(lines))


def format_journal_context(config: dict, player: str) -> str:
    """Format journal for injection into the system prompt.
    Returns empty string if no journal exists."""
    content = read_journal(config, player)
    if not content:
        return ""
    return f"\n=== PLAYER JOURNAL: {player} ===\n{content}\n=== END JOURNAL ===\n"


def list_journals(config: dict) -> list:
    """List all players who have journals."""
    d = _journal_dir(config)
    if not d.exists():
        return []
    return [f.stem for f in d.glob("*.txt") if f.stat().st_size > 0]


# ── Tool handlers ──────────────────────────────────────────────────────────

def handle_journal_read(config: dict, arguments: dict) -> dict:
    """Tool handler for reading a player journal."""
    player = arguments.get("player", "")
    if not player:
        return {"ok": False, "error": "player name required"}
    content = read_journal(config, player)
    if content:
        return {"ok": True, "player": player, "journal": content}
    return {"ok": True, "player": player, "journal": "", "note": "No journal exists for this player yet."}


def handle_journal_write(config: dict, arguments: dict) -> dict:
    """Tool handler for writing/overwriting a player journal.
    The model has free reign — it decides what to keep and what to overwrite."""
    player = arguments.get("player", "")
    content = arguments.get("content", "")
    if not player:
        return {"ok": False, "error": "player name required"}
    if not content:
        return {"ok": False, "error": "content required"}
    write_journal(config, player, content)
    lines = len([l for l in content.strip().split("\n") if l.strip()])
    return {"ok": True, "player": player, "lines": lines}
