"""
PM-016: HANDOFF Logger Integration
Auto-update HANDOFF.md after iterations for Genesis.

Acceptance Criteria:
- [x] GIVEN iteration completes WHEN logged THEN HANDOFF updated
- [x] AND includes: timestamp, task_id, model, result, cost
- [x] AND human-readable format

Dependencies: PM-009
"""

import os
import json
import logging
from datetime import datetime
from typing import Optional, Dict, Any, List
from dataclasses import dataclass, field
from pathlib import Path
import fcntl
from contextlib import contextmanager

logger = logging.getLogger(__name__)


@dataclass
class HandoffEntry:
    """Entry for HANDOFF.md logging."""
    task_id: str
    timestamp: str
    model: str
    result: str  # "success", "escalated", "failed", "human_review"
    cost: float

    # Optional details
    tier: int = 1
    attempts: int = 1
    duration_ms: int = 0
    error_message: Optional[str] = None
    output_summary: Optional[str] = None
    notes: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        return {
            "task_id": self.task_id,
            "timestamp": self.timestamp,
            "model": self.model,
            "result": self.result,
            "cost": self.cost,
            "tier": self.tier,
            "attempts": self.attempts,
            "duration_ms": self.duration_ms,
            "error_message": self.error_message,
            "output_summary": self.output_summary,
            "notes": self.notes
        }

    def to_markdown(self) -> str:
        """Convert to human-readable markdown format."""
        # Status emoji
        status_emoji = {
            "success": "SUCCESS",
            "escalated": "ESCALATED",
            "failed": "FAILED",
            "human_review": "NEEDS REVIEW"
        }.get(self.result, self.result.upper())

        md = f"""### {self.task_id}
**Time:** {self.timestamp}
**Status:** {status_emoji}
**Model:** {self.model} (Tier {self.tier})
**Attempts:** {self.attempts}
**Cost:** ${self.cost:.4f}
**Duration:** {self.duration_ms}ms
"""

        if self.error_message:
            md += f"\n**Error:** {self.error_message[:200]}\n"

        if self.output_summary:
            md += f"\n**Output:** {self.output_summary[:300]}\n"

        if self.notes:
            md += f"\n**Notes:** {self.notes}\n"

        md += "\n---\n"

        return md


class HandoffLogger:
    """
    Auto-update HANDOFF.md after iterations.

    Features:
    - Append entries in human-readable format
    - Include timestamp, task_id, model, result, cost
    - Thread-safe file writing
    - Daily rotation support
    - Summary generation
    """

    DEFAULT_PATH = "HANDOFF.md"
    HEADER_TEMPLATE = """# Genesis Execution Handoff Log

This file is auto-updated after each task iteration.
Last updated: {timestamp}

---

## Recent Executions

"""

    def __init__(self,
                 handoff_path: Optional[str] = None,
                 max_entries: int = 100,
                 auto_rotate: bool = True):
        """
        Initialize HandoffLogger.

        Args:
            handoff_path: Path to HANDOFF.md
            max_entries: Maximum entries before rotation
            auto_rotate: Enable daily rotation
        """
        self.handoff_path = Path(handoff_path or self.DEFAULT_PATH)
        self.max_entries = max_entries
        self.auto_rotate = auto_rotate

        # Entry history (in memory)
        self._entries: List[HandoffEntry] = []

        # Ensure file exists
        self._ensure_file_exists()

    def _ensure_file_exists(self) -> None:
        """Ensure HANDOFF.md exists with header."""
        if not self.handoff_path.exists():
            try:
                header = self.HEADER_TEMPLATE.format(
                    timestamp=datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
                )
                with open(self.handoff_path, "w") as f:
                    f.write(header)
                logger.info(f"Created HANDOFF.md at {self.handoff_path}")
            except Exception as e:
                logger.warning(f"Failed to create HANDOFF.md: {e}")

    @contextmanager
    def _file_lock(self, filepath: Path, mode: str = "a"):
        """Context manager for thread-safe file writing."""
        f = None
        try:
            f = open(filepath, mode)
            fcntl.flock(f.fileno(), fcntl.LOCK_EX)
            yield f
        finally:
            if f:
                fcntl.flock(f.fileno(), fcntl.LOCK_UN)
                f.close()

    def log_iteration(self,
                     task_id: str,
                     model: str,
                     result: str,
                     cost: float,
                     tier: int = 1,
                     attempts: int = 1,
                     duration_ms: int = 0,
                     error_message: Optional[str] = None,
                     output_summary: Optional[str] = None,
                     notes: Optional[str] = None) -> HandoffEntry:
        """
        Log an iteration to HANDOFF.md.

        Args:
            task_id: Task identifier
            model: Model used
            result: Result status
            cost: Total cost
            tier: Final tier
            attempts: Total attempts
            duration_ms: Duration
            error_message: Error if failed
            output_summary: Summary of output
            notes: Additional notes

        Returns:
            HandoffEntry that was logged
        """
        entry = HandoffEntry(
            task_id=task_id,
            timestamp=datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC"),
            model=model,
            result=result,
            cost=cost,
            tier=tier,
            attempts=attempts,
            duration_ms=duration_ms,
            error_message=error_message,
            output_summary=output_summary,
            notes=notes
        )

        # Store in memory
        self._entries.append(entry)

        # Write to file
        self._write_entry(entry)

        # Check for rotation
        if self.auto_rotate and len(self._entries) >= self.max_entries:
            self._rotate_file()

        logger.info(f"Logged to HANDOFF.md: {task_id} - {result}")

        return entry

    def _write_entry(self, entry: HandoffEntry) -> None:
        """Write entry to file."""
        try:
            with self._file_lock(self.handoff_path, "a") as f:
                f.write(entry.to_markdown())
        except Exception as e:
            logger.error(f"Failed to write to HANDOFF.md: {e}")

    def _rotate_file(self) -> None:
        """Rotate HANDOFF.md to archive."""
        try:
            timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S")
            archive_path = self.handoff_path.with_suffix(f".{timestamp}.md")

            # Rename current file
            self.handoff_path.rename(archive_path)
            logger.info(f"Rotated HANDOFF.md to {archive_path}")

            # Create new file
            self._ensure_file_exists()

            # Clear memory entries
            self._entries = []

        except Exception as e:
            logger.error(f"Failed to rotate HANDOFF.md: {e}")

    def log_from_execution_result(self, result: Dict[str, Any]) -> HandoffEntry:
        """
        Log from a TieredExecutor result dict.

        Args:
            result: ExecutionResult.to_dict() output

        Returns:
            HandoffEntry
        """
        return self.log_iteration(
            task_id=result.get("task_id", "unknown"),
            model=result.get("model", "unknown"),
            result=result.get("status", "unknown"),
            cost=result.get("total_cost", 0.0),
            tier=result.get("final_tier", 1),
            attempts=result.get("total_attempts", 1),
            duration_ms=result.get("total_duration_ms", 0),
            error_message=result.get("error_message"),
            output_summary=result.get("output", "")[:200] if result.get("output") else None
        )

    def add_summary(self, summary_text: str) -> None:
        """Add a summary section to HANDOFF.md."""
        try:
            summary_entry = f"""
## Summary - {datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")}

{summary_text}

---

"""
            with self._file_lock(self.handoff_path, "a") as f:
                f.write(summary_entry)
        except Exception as e:
            logger.error(f"Failed to add summary: {e}")

    def add_daily_summary(self) -> str:
        """Generate and add daily summary."""
        if not self._entries:
            return "No entries to summarize"

        # Calculate stats
        total = len(self._entries)
        successful = sum(1 for e in self._entries if e.result == "success")
        failed = sum(1 for e in self._entries if e.result in ["failed", "human_review"])
        total_cost = sum(e.cost for e in self._entries)
        avg_cost = total_cost / total if total else 0

        # By tier
        tier_counts = {1: 0, 2: 0, 3: 0}
        for e in self._entries:
            if e.tier in tier_counts:
                tier_counts[e.tier] += 1

        summary = f"""### Daily Statistics

- **Total Tasks:** {total}
- **Successful:** {successful} ({successful/total*100:.1f}%)
- **Failed/Review:** {failed} ({failed/total*100:.1f}%)
- **Total Cost:** ${total_cost:.4f}
- **Avg Cost/Task:** ${avg_cost:.4f}

**By Tier:**
- Tier 1: {tier_counts[1]} tasks
- Tier 2: {tier_counts[2]} tasks
- Tier 3: {tier_counts[3]} tasks
"""

        self.add_summary(summary)
        return summary

    def get_recent_entries(self, count: int = 10) -> List[HandoffEntry]:
        """Get most recent entries."""
        return self._entries[-count:] if self._entries else []

    def get_statistics(self) -> Dict[str, Any]:
        """Get statistics from logged entries."""
        if not self._entries:
            return {"total_entries": 0}

        return {
            "total_entries": len(self._entries),
            "successful": sum(1 for e in self._entries if e.result == "success"),
            "failed": sum(1 for e in self._entries if e.result in ["failed", "human_review"]),
            "total_cost": sum(e.cost for e in self._entries),
            "avg_attempts": sum(e.attempts for e in self._entries) / len(self._entries),
            "by_tier": {
                tier: sum(1 for e in self._entries if e.tier == tier)
                for tier in [1, 2, 3]
            },
            "by_result": {
                result: sum(1 for e in self._entries if e.result == result)
                for result in ["success", "escalated", "failed", "human_review"]
            }
        }


# Singleton instance
_logger: Optional[HandoffLogger] = None


def get_handoff_logger() -> HandoffLogger:
    """Get or create global HandoffLogger instance."""
    global _logger
    if _logger is None:
        _logger = HandoffLogger()
    return _logger


def log_to_handoff(task_id: str,
                  model: str,
                  result: str,
                  cost: float,
                  **kwargs) -> HandoffEntry:
    """Convenience function to log to HANDOFF.md."""
    return get_handoff_logger().log_iteration(
        task_id=task_id,
        model=model,
        result=result,
        cost=cost,
        **kwargs
    )


if __name__ == "__main__":
    # Test the HandoffLogger
    logging.basicConfig(level=logging.INFO)

    # Use a test file
    logger_instance = HandoffLogger(handoff_path="HANDOFF_TEST.md")

    # Log some test entries
    logger_instance.log_iteration(
        task_id="test-001",
        model="gemini-flash",
        result="success",
        cost=0.01,
        tier=1,
        attempts=3,
        duration_ms=1500
    )

    logger_instance.log_iteration(
        task_id="test-002",
        model="claude-sonnet",
        result="success",
        cost=0.15,
        tier=2,
        attempts=25,
        duration_ms=5000
    )

    logger_instance.log_iteration(
        task_id="test-003",
        model="claude-opus",
        result="human_review",
        cost=0.75,
        tier=3,
        attempts=40,
        duration_ms=30000,
        error_message="All tiers failed - complex dependency issue"
    )

    print("\nStatistics:")
    print(json.dumps(logger_instance.get_statistics(), indent=2))

    # Generate daily summary
    print("\nDaily Summary:")
    print(logger_instance.add_daily_summary())
