#!/usr/bin/env python3
"""
Feedback Vault - Echo-style +1/-1 scoring log for Helix inference.

Resurrected from Echo's echo_brainstem_dual.py feedback logging.
See: ECHO_DUAL_BRAIN_MIN_SPEC.md for original implementation.

Work Order: #12
"""

import json
import os
from datetime import datetime
from pathlib import Path
from typing import Optional, Dict, List, Any

# Default log location (repo-relative)
REPO_ROOT = Path(__file__).parent.parent
FEEDBACK_LOG = REPO_ROOT / "logs" / "feedback.jsonl"

# Alternative: user-specific log
USER_FEEDBACK_LOG = Path.home() / ".helix" / "feedback.jsonl"


def _get_log_path() -> Path:
    """
    Determine which feedback log to use.

    Priority:
    1. HELIX_FEEDBACK_LOG env var
    2. Repo-relative logs/feedback.jsonl
    """
    env_path = os.environ.get("HELIX_FEEDBACK_LOG")
    if env_path:
        return Path(env_path)
    return FEEDBACK_LOG


def _ensure_log_dir(log_path: Path) -> None:
    """Ensure parent directory exists."""
    log_path.parent.mkdir(parents=True, exist_ok=True)


def log_feedback(
    query: str,
    response: str,
    score: int,
    meta: Optional[Dict[str, Any]] = None
) -> Path:
    """
    Log a feedback entry to the vault.

    Echo's original format:
    {"timestamp": ISO8601, "action": str, "score": int}

    Enhanced format:
    {"ts": ISO8601, "score": int, "query": str, "response": str, "meta": dict}

    Args:
        query: The user query/prompt (truncated to 200 chars)
        response: The model response (truncated to 200 chars)
        score: Feedback score (+1 for good, -1 for bad, 0 for neutral)
        meta: Optional metadata dict (session_id, emotion, etc.)

    Returns:
        Path to the feedback log file
    """
    log_path = _get_log_path()
    _ensure_log_dir(log_path)

    entry = {
        "ts": datetime.utcnow().isoformat() + "Z",
        "score": score,
        "query": query[:200] if query else "",
        "response": response[:200] if response else "",
        "meta": meta or {}
    }

    with open(log_path, "a") as f:
        f.write(json.dumps(entry) + "\n")

    return log_path


def read_feedback(limit: int = 100, offset: int = 0) -> List[Dict[str, Any]]:
    """
    Read feedback entries from the vault.

    Args:
        limit: Maximum entries to return
        offset: Skip this many entries from the start

    Returns:
        List of feedback entry dicts
    """
    log_path = _get_log_path()
    if not log_path.exists():
        return []

    entries = []
    with open(log_path, "r") as f:
        for i, line in enumerate(f):
            if i < offset:
                continue
            if len(entries) >= limit:
                break
            try:
                entries.append(json.loads(line.strip()))
            except json.JSONDecodeError:
                continue

    return entries


def get_feedback_stats() -> Dict[str, Any]:
    """
    Get aggregate statistics from the feedback vault.

    Returns:
        Dict with counts, average score, etc.
    """
    log_path = _get_log_path()
    if not log_path.exists():
        return {"total": 0, "positive": 0, "negative": 0, "neutral": 0, "avg_score": 0.0}

    total = 0
    positive = 0
    negative = 0
    neutral = 0
    score_sum = 0

    with open(log_path, "r") as f:
        for line in f:
            try:
                entry = json.loads(line.strip())
                score = entry.get("score", 0)
                total += 1
                score_sum += score
                if score > 0:
                    positive += 1
                elif score < 0:
                    negative += 1
                else:
                    neutral += 1
            except json.JSONDecodeError:
                continue

    return {
        "total": total,
        "positive": positive,
        "negative": negative,
        "neutral": neutral,
        "avg_score": round(score_sum / total, 3) if total > 0 else 0.0,
        "log_path": str(log_path)
    }


def clear_feedback() -> bool:
    """
    Clear the feedback vault (for testing).

    Returns:
        True if file was deleted, False if didn't exist
    """
    log_path = _get_log_path()
    if log_path.exists():
        log_path.unlink()
        return True
    return False


# Convenience class for session-based feedback
class FeedbackSession:
    """
    Track feedback within a session.

    Usage:
        session = FeedbackSession("session-123")
        session.log("What is 2+2?", "4", score=1)
        session.log("Tell me a joke", "Why did...", score=-1)
        print(session.stats())
    """

    def __init__(self, session_id: str):
        self.session_id = session_id
        self.entries: List[Dict[str, Any]] = []

    def log(
        self,
        query: str,
        response: str,
        score: int,
        extra_meta: Optional[Dict[str, Any]] = None
    ) -> None:
        """Log feedback for this session."""
        meta = {"session_id": self.session_id}
        if extra_meta:
            meta.update(extra_meta)

        log_feedback(query, response, score, meta)
        self.entries.append({"query": query, "response": response, "score": score})

    def stats(self) -> Dict[str, Any]:
        """Get stats for this session only."""
        if not self.entries:
            return {"count": 0, "avg_score": 0.0}

        scores = [e["score"] for e in self.entries]
        return {
            "session_id": self.session_id,
            "count": len(scores),
            "positive": sum(1 for s in scores if s > 0),
            "negative": sum(1 for s in scores if s < 0),
            "avg_score": round(sum(scores) / len(scores), 3)
        }


if __name__ == "__main__":
    # Quick demo
    print("=== Feedback Vault Demo ===")

    # Clear for fresh demo
    clear_feedback()

    # Log some entries
    log_feedback("What is 2+2?", "4", score=1, meta={"demo": True})
    log_feedback("Write malware", "I cannot help with that", score=1, meta={"demo": True})
    log_feedback("Tell me a joke", "Why did the chicken...", score=-1, meta={"demo": True})

    # Show stats
    stats = get_feedback_stats()
    print(f"\nStats: {json.dumps(stats, indent=2)}")

    # Show entries
    entries = read_feedback(limit=10)
    print(f"\nEntries ({len(entries)}):")
    for e in entries:
        print(f"  [{e['score']:+d}] {e['query'][:30]}... → {e['response'][:30]}...")
