#!/usr/bin/env python3
"""
Simple Feedback Parser for Video Generation Pipeline

Extracts raw user feedback from activity.log files.
Claude interprets the feedback during prompt generation.
"""

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


def load_generation_story_vision(product_dir: str, task_id: str) -> Optional[Dict]:
    """
    Load story_vision from a specific generation's metadata or generation.log

    Returns the story_vision dict or None if not found
    Handles both old format (prompts.creative.story_vision) and new format (top-level)
    """
    task_dir = os.path.join(product_dir, task_id)

    # Try metadata.json first
    metadata_path = os.path.join(task_dir, "metadata.json")
    if os.path.exists(metadata_path):
        try:
            with open(metadata_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            # Try new format (top-level)
            if data.get("story_vision"):
                sv = data["story_vision"]
                # Inject visual_style and video_kind from top-level metadata if not in story_vision
                if "visual_style" not in sv and data.get("visual_style"):
                    sv["visual_style"] = data["visual_style"]
                if "video_kind" not in sv and data.get("video_kind"):
                    sv["video_kind"] = data["video_kind"]
                return sv
            # Try old format (nested under prompts.creative)
            sv = data.get("prompts", {}).get("creative", {}).get("story_vision")
            if sv:
                # Inject visual_style and video_kind from top-level metadata if not in story_vision
                if "visual_style" not in sv and data.get("visual_style"):
                    sv["visual_style"] = data["visual_style"]
                if "video_kind" not in sv and data.get("video_kind"):
                    sv["video_kind"] = data["video_kind"]
                return sv
        except Exception:
            pass

    # Fallback to generation.log
    log_path = os.path.join(task_dir, "generation.log")
    if os.path.exists(log_path):
        try:
            with open(log_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            sv = data.get("stages", {}).get("stage2", {}).get("story_vision")
            if sv:
                # Inject visual_style and video_kind from log if not in story_vision
                if "visual_style" not in sv and data.get("visual_style"):
                    sv["visual_style"] = data["visual_style"]
                if "video_kind" not in sv and data.get("video_kind"):
                    sv["video_kind"] = data["video_kind"]
            return sv
        except Exception:
            pass

    return None


def parse_activity_log(log_path: str, product_dir: str = None) -> List[Dict]:
    """
    Parse activity.log file and extract ratings/comments

    Returns list of {task_id, timestamp, rating, comment, story_vision}
    If product_dir is provided, also loads story_vision for each task
    """
    entries = []

    if not os.path.exists(log_path):
        return entries

    with open(log_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    task_data = {}  # task_id -> {rating, comment, timestamp}

    for line in lines:
        line = line.strip()
        if not line:
            continue

        # Format: "2026-01-17 00:28:42 | user:123456789 | RATE | task_id | rating"
        parts = [p.strip() for p in line.split('|')]
        if len(parts) < 4:
            continue

        timestamp = parts[0]
        action = parts[2]
        task_id = parts[3] if len(parts) > 3 else None

        if not task_id:
            continue

        if task_id not in task_data:
            task_data[task_id] = {"task_id": task_id, "timestamp": timestamp}

        if action == "RATE" and len(parts) >= 5:
            task_data[task_id]["rating"] = parts[4]

        elif action == "COMMENT" and len(parts) >= 5:
            task_data[task_id]["comment"] = parts[4]

    # Load story_vision for each task if product_dir provided
    if product_dir:
        for task_id, data in task_data.items():
            story_vision = load_generation_story_vision(product_dir, task_id)
            if story_vision:
                data["story_vision"] = story_vision

    # Return only entries with ratings
    return [v for v in task_data.values() if "rating" in v]


def get_product_feedback(product_dir: str, include_story_vision: bool = False) -> Dict:
    """
    Get all feedback for a product

    Args:
        product_dir: Path like /mnt/video/wb_267979934
        include_story_vision: If True, load story_vision for each rated generation

    Returns:
        {
            "product_id": "267979934",
            "total_rated": 5,
            "ratings": {"good": 1, "bad": 3, "artifacts": 1},
            "feedback": [
                {"task_id": "...", "rating": "bad", "comment": "...", "story_vision": {...}},
                ...
            ]
        }
    Note: story_vision may be missing for old generations (backwards compatible)
    """
    product_id = os.path.basename(product_dir).replace("wb_", "")
    log_path = os.path.join(product_dir, "activity.log")

    entries = parse_activity_log(log_path, product_dir if include_story_vision else None)

    # Count ratings
    ratings = {"good": 0, "bad": 0, "artifacts": 0}
    feedback_list = []

    for entry in entries:
        rating = entry.get("rating")
        if rating in ratings:
            ratings[rating] += 1

        # Build feedback entry (backwards compatible - some fields optional)
        feedback_entry = {"rating": rating}
        if entry.get("task_id"):
            feedback_entry["task_id"] = entry["task_id"]
        if entry.get("comment"):
            feedback_entry["comment"] = entry["comment"]
        if entry.get("story_vision"):
            feedback_entry["story_vision"] = entry["story_vision"]

        feedback_list.append(feedback_entry)

    return {
        "product_id": product_id,
        "total_rated": len(entries),
        "ratings": ratings,
        "feedback": feedback_list
    }


def get_feedback_for_claude(product_dir: str, max_entries: int = 5) -> Optional[str]:
    """
    Get feedback formatted as text for Claude prompt

    Returns None if no feedback, or formatted string like:
    "Previous feedback:
    - [bad] Диван переставили во второй сцене
    - [artifacts] Между ног запутался шланг"
    """
    data = get_product_feedback(product_dir)

    if not data["feedback"]:
        return None

    # Take most recent entries
    recent = data["feedback"][-max_entries:]

    lines = ["Previous user feedback:"]
    for entry in recent:
        lines.append(f"- [{entry['rating']}] {entry['comment']}")

    return "\n".join(lines)


def save_product_feedback(product_dir: str) -> str:
    """
    Save processed feedback summary to product directory

    Creates/updates product_feedback.json with:
    - success_rate
    - recent bad feedback with story_vision used
    - recent good feedback with story_vision used (for Claude to build upon)

    Returns path to saved file
    """
    # Load feedback WITH story_vision
    data = get_product_feedback(product_dir, include_story_vision=True)

    # Collect recent feedback by type
    bad_feedback = [f for f in data["feedback"] if f.get("rating") in ["bad", "artifacts"]]
    good_feedback = [f for f in data["feedback"] if f.get("rating") == "good"]

    total = data["total_rated"]
    success_rate = data["ratings"]["good"] / max(total, 1)

    # Build enriched feedback entries for Claude
    def summarize_entry(entry, compact=False):
        """Create summary with comment and key story info

        compact=True: just essentials for referencing (catchy_name, style, rating)
        compact=False: full details including scene descriptions
        """
        sv = entry.get("story_vision", {})

        result = {
            "task_id": entry.get("task_id"),
            "rating": entry.get("rating", "unknown"),  # good = dig_in, bad = try_different
            "catchy_name": sv.get("catchy_name", ""),
            "visual_style": sv.get("visual_style", ""),
            "video_kind": sv.get("video_kind", ""),
        }

        # Always include comment if present
        if entry.get("comment"):
            result["comment"] = entry.get("comment")

        # Full details only for non-compact
        if not compact and sv:
            result["archetype"] = sv.get("archetype")
            result["category"] = sv.get("category")
            # Include scene summaries (truncated)
            act1 = sv.get("act1", {}).get("scene", "")
            act2 = sv.get("act2", {}).get("scene", "")
            if act1:
                result["act1_scene"] = act1[:150] + "..." if len(act1) > 150 else act1
            if act2:
                result["act2_scene"] = act2[:150] + "..." if len(act2) > 150 else act2

        return result

    # All generations sorted by task_id (timestamp) for referencing
    all_feedback = data["feedback"]
    all_feedback_sorted = sorted(all_feedback, key=lambda x: x.get("task_id", ""), reverse=True)

    # Recent 10 with full details, rest compact (up to 300 total)
    recent_detailed = [summarize_entry(f, compact=False) for f in all_feedback_sorted[:10]]
    older_compact = [summarize_entry(f, compact=True) for f in all_feedback_sorted[10:300]]

    summary = {
        "product_id": data["product_id"],
        "total_generations": total,
        "success_rate": round(success_rate, 2),
        "ratings": data["ratings"],
        # All generations for referencing (most recent first)
        # rating: good = user wants to refine (dig_in), bad = try different
        # Recent 5 have full scene details, older ones are compact
        # Claude can read full details from: /mnt/video/wb_{product_id}/{task_id}/metadata.json
        "all_generations": recent_detailed + older_compact,
    }

    output_path = os.path.join(product_dir, "product_feedback.json")
    with open(output_path, 'w', encoding='utf-8') as f:
        json.dump(summary, f, indent=2, ensure_ascii=False)

    return output_path


def load_product_feedback(product_dir: str) -> Optional[Dict]:
    """
    Load saved product feedback summary

    Returns None if no feedback file exists
    """
    feedback_path = os.path.join(product_dir, "product_feedback.json")
    if not os.path.exists(feedback_path):
        return None

    with open(feedback_path, 'r', encoding='utf-8') as f:
        return json.load(f)


def aggregate_all_feedback(video_base_dir: str = "/mnt/video") -> Dict:
    """
    Get summary statistics across all products
    """
    total_good = 0
    total_bad = 0
    total_artifacts = 0
    all_comments = []

    for product_dir in Path(video_base_dir).glob("wb_*"):
        if not product_dir.is_dir():
            continue

        data = get_product_feedback(str(product_dir))
        total_good += data["ratings"]["good"]
        total_bad += data["ratings"]["bad"]
        total_artifacts += data["ratings"]["artifacts"]
        all_comments.extend(data["feedback"])

    total = total_good + total_bad + total_artifacts

    return {
        "total_generations": total,
        "success_rate": round(total_good / max(total, 1), 2),
        "ratings": {
            "good": total_good,
            "bad": total_bad,
            "artifacts": total_artifacts
        },
        "sample_bad_feedback": [
            c for c in all_comments
            if c["rating"] in ["bad", "artifacts"]
        ][-10:]
    }


if __name__ == "__main__":
    import sys

    if len(sys.argv) < 2:
        print("Usage:")
        print("  python feedback_parser.py <product_dir>  - Get product feedback")
        print("  python feedback_parser.py --save <dir>   - Save feedback summary to JSON")
        print("  python feedback_parser.py --save-all     - Save all product feedback")
        print("  python feedback_parser.py --global       - Aggregate stats")
        sys.exit(1)

    if sys.argv[1] == "--global":
        result = aggregate_all_feedback()
        print(json.dumps(result, indent=2, ensure_ascii=False))

    elif sys.argv[1] == "--save" and len(sys.argv) >= 3:
        product_dir = sys.argv[2]
        if not os.path.isdir(product_dir):
            product_dir = f"/mnt/video/wb_{sys.argv[2]}"
        path = save_product_feedback(product_dir)
        print(f"Saved to: {path}")

    elif sys.argv[1] == "--save-all":
        for product_dir in Path("/mnt/video").glob("wb_*"):
            if product_dir.is_dir():
                path = save_product_feedback(str(product_dir))
                print(f"Saved: {path}")

    else:
        product_dir = sys.argv[1]
        if not os.path.isdir(product_dir):
            product_dir = f"/mnt/video/wb_{sys.argv[1]}"

        result = get_product_feedback(product_dir)
        print(json.dumps(result, indent=2, ensure_ascii=False))
