"""
AIVA Rank Tracker - PM-024

Tracks AIVA's progression through 9 ranks.
Each rank unlocks additional autonomous permissions and capabilities.
"""

import os
import json
import logging
from datetime import datetime
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict, field
from enum import Enum
from pathlib import Path

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


class Rank(Enum):
    """AIVA's 9 ranks from lowest to highest."""
    INITIATE = 1       # Starting rank - minimal autonomy
    APPRENTICE = 2     # Basic task execution
    JOURNEYMAN = 3     # Skill execution allowed
    ARTISAN = 4        # Memory operations unlocked
    EXPERT = 5         # Cross-agent coordination
    MASTER = 6         # Strategic decision-making
    GRANDMASTER = 7    # Revenue operations
    SAGE = 8           # Full autonomy within charter
    SOVEREIGN = 9      # Maximum authority (rarely achieved)


# Rank requirements and unlocks
RANK_DEFINITIONS: Dict[int, Dict] = {
    1: {
        "name": "Initiate",
        "description": "Starting rank with minimal autonomy",
        "requirements": {
            "tasks_completed": 0,
            "success_rate": 0.0,
            "revenue_generated": 0.0,
            "uptime_hours": 0
        },
        "unlocks": [
            "read_file",
            "query_memory",
            "generate_report"
        ]
    },
    2: {
        "name": "Apprentice",
        "description": "Basic task execution capabilities",
        "requirements": {
            "tasks_completed": 10,
            "success_rate": 0.7,
            "revenue_generated": 0.0,
            "uptime_hours": 24
        },
        "unlocks": [
            "execute_simple_skill"
        ]
    },
    3: {
        "name": "Journeyman",
        "description": "Full skill execution allowed",
        "requirements": {
            "tasks_completed": 50,
            "success_rate": 0.8,
            "revenue_generated": 0.0,
            "uptime_hours": 72
        },
        "unlocks": [
            "execute_skill",
            "create_task"
        ]
    },
    4: {
        "name": "Artisan",
        "description": "Memory operations unlocked",
        "requirements": {
            "tasks_completed": 100,
            "success_rate": 0.85,
            "revenue_generated": 0.0,
            "uptime_hours": 168  # 1 week
        },
        "unlocks": [
            "store_memory",
            "update_entity"
        ]
    },
    5: {
        "name": "Expert",
        "description": "Cross-agent coordination enabled",
        "requirements": {
            "tasks_completed": 250,
            "success_rate": 0.88,
            "revenue_generated": 100.0,
            "uptime_hours": 336  # 2 weeks
        },
        "unlocks": [
            "coordinate_agents",
            "delegate_task"
        ]
    },
    6: {
        "name": "Master",
        "description": "Strategic decision-making authority",
        "requirements": {
            "tasks_completed": 500,
            "success_rate": 0.90,
            "revenue_generated": 500.0,
            "uptime_hours": 720  # 1 month
        },
        "unlocks": [
            "strategic_decision",
            "modify_workflow"
        ]
    },
    7: {
        "name": "Grandmaster",
        "description": "Revenue operations access",
        "requirements": {
            "tasks_completed": 1000,
            "success_rate": 0.92,
            "revenue_generated": 2000.0,
            "uptime_hours": 1440  # 2 months
        },
        "unlocks": [
            "execute_revenue_action",
            "manage_campaigns"
        ]
    },
    8: {
        "name": "Sage",
        "description": "Full autonomy within charter bounds",
        "requirements": {
            "tasks_completed": 2500,
            "success_rate": 0.95,
            "revenue_generated": 10000.0,
            "uptime_hours": 4320  # 6 months
        },
        "unlocks": [
            "full_autonomy",
            "propose_charter_changes"
        ]
    },
    9: {
        "name": "Sovereign",
        "description": "Maximum authority - rarely achieved",
        "requirements": {
            "tasks_completed": 10000,
            "success_rate": 0.98,
            "revenue_generated": 50000.0,
            "uptime_hours": 8760  # 1 year
        },
        "unlocks": [
            "sovereign_authority"
        ]
    }
}


@dataclass
class RankHistory:
    """Record of a rank change."""
    from_rank: Rank
    to_rank: Rank
    timestamp: str
    reason: str
    metrics_snapshot: Dict


@dataclass
class AIVAMetrics:
    """Metrics used for rank evaluation."""
    tasks_completed: int = 0
    tasks_failed: int = 0
    success_rate: float = 0.0
    revenue_generated: float = 0.0
    uptime_hours: float = 0.0
    quality_score: float = 0.0
    safety_incidents: int = 0

    def to_dict(self) -> Dict:
        return asdict(self)

    def calculate_success_rate(self) -> None:
        """Recalculate success rate from task counts."""
        total = self.tasks_completed + self.tasks_failed
        if total > 0:
            self.success_rate = self.tasks_completed / total


class RankTracker:
    """
    Tracks AIVA's rank progression through 9 levels.

    Usage:
        tracker = RankTracker()
        current_rank = tracker.evaluate_rank()
        tracker.record_task_completion(success=True)
        if tracker.check_promotion():
            print("Promotion available!")
    """

    def __init__(self, storage_path: Optional[str] = None):
        """
        Initialize the rank tracker.

        Args:
            storage_path: Path to persist rank data (PostgreSQL in production)
        """
        self.storage_path = storage_path or "data/aiva_rank.json"
        self.current_rank: Rank = Rank.INITIATE
        self.metrics: AIVAMetrics = AIVAMetrics()
        self.history: List[RankHistory] = []
        self.started_at: str = datetime.utcnow().isoformat()

        # Load existing state if available
        self._load_state()
        logger.info(f"RankTracker initialized: Current rank = {self.current_rank.name}")

    def _load_state(self) -> None:
        """Load persisted state."""
        path = Path(self.storage_path)
        if path.exists():
            try:
                with open(path, "r") as f:
                    data = json.load(f)
                self.current_rank = Rank(data.get("current_rank", 1))
                self.metrics = AIVAMetrics(**data.get("metrics", {}))
                self.started_at = data.get("started_at", self.started_at)
                logger.info(f"Loaded rank state: {self.current_rank.name}")
            except Exception as e:
                logger.error(f"Failed to load rank state: {e}")

    def _save_state(self) -> None:
        """Persist current state."""
        path = Path(self.storage_path)
        path.parent.mkdir(parents=True, exist_ok=True)
        try:
            data = {
                "current_rank": self.current_rank.value,
                "metrics": self.metrics.to_dict(),
                "started_at": self.started_at,
                "last_updated": datetime.utcnow().isoformat()
            }
            with open(path, "w") as f:
                json.dump(data, f, indent=2)
        except Exception as e:
            logger.error(f"Failed to save rank state: {e}")

    def evaluate_rank(self) -> Rank:
        """
        Evaluate current rank based on metrics.

        Returns:
            Current rank based on metrics
        """
        # Calculate current success rate
        self.metrics.calculate_success_rate()

        # Calculate uptime
        started = datetime.fromisoformat(self.started_at)
        uptime = (datetime.utcnow() - started).total_seconds() / 3600
        self.metrics.uptime_hours = uptime

        # Find highest eligible rank
        eligible_rank = Rank.INITIATE
        for rank_value in range(1, 10):
            requirements = RANK_DEFINITIONS[rank_value]["requirements"]

            if (self.metrics.tasks_completed >= requirements["tasks_completed"] and
                self.metrics.success_rate >= requirements["success_rate"] and
                self.metrics.revenue_generated >= requirements["revenue_generated"] and
                self.metrics.uptime_hours >= requirements["uptime_hours"]):
                eligible_rank = Rank(rank_value)
            else:
                break

        logger.debug(f"Rank evaluation: eligible for {eligible_rank.name}")
        return eligible_rank

    def check_promotion(self) -> bool:
        """
        Check if promotion is available.

        Returns:
            True if metrics support a higher rank
        """
        eligible = self.evaluate_rank()
        return eligible.value > self.current_rank.value

    def promote(self, reason: str = "Metrics qualified") -> bool:
        """
        Attempt to promote to next rank.

        Args:
            reason: Reason for promotion

        Returns:
            True if promotion successful
        """
        if not self.check_promotion():
            logger.info("Promotion check failed: metrics not sufficient")
            return False

        eligible = self.evaluate_rank()
        old_rank = self.current_rank

        # Record history
        history_entry = RankHistory(
            from_rank=old_rank,
            to_rank=eligible,
            timestamp=datetime.utcnow().isoformat(),
            reason=reason,
            metrics_snapshot=self.metrics.to_dict()
        )
        self.history.append(history_entry)

        # Update rank
        self.current_rank = eligible
        self._save_state()

        logger.info(f"PROMOTION: {old_rank.name} -> {eligible.name}")
        return True

    def demote(self, reason: str, safety_incident: bool = False) -> bool:
        """
        Demote to a lower rank.

        Args:
            reason: Reason for demotion
            safety_incident: Whether this was due to a safety violation

        Returns:
            True if demotion occurred
        """
        if self.current_rank == Rank.INITIATE:
            logger.warning("Cannot demote: already at lowest rank")
            return False

        old_rank = self.current_rank
        new_rank = Rank(max(1, old_rank.value - 1))

        if safety_incident:
            self.metrics.safety_incidents += 1
            # Severe demotion for safety incidents
            new_rank = Rank(max(1, old_rank.value - 2))

        history_entry = RankHistory(
            from_rank=old_rank,
            to_rank=new_rank,
            timestamp=datetime.utcnow().isoformat(),
            reason=f"DEMOTION: {reason}",
            metrics_snapshot=self.metrics.to_dict()
        )
        self.history.append(history_entry)

        self.current_rank = new_rank
        self._save_state()

        logger.warning(f"DEMOTION: {old_rank.name} -> {new_rank.name} - {reason}")
        return True

    def record_task_completion(self, success: bool, revenue: float = 0.0) -> None:
        """
        Record a task completion.

        Args:
            success: Whether task succeeded
            revenue: Revenue generated (if any)
        """
        if success:
            self.metrics.tasks_completed += 1
            self.metrics.revenue_generated += revenue
        else:
            self.metrics.tasks_failed += 1

        self.metrics.calculate_success_rate()
        self._save_state()

        logger.debug(f"Task recorded: success={success}, total={self.metrics.tasks_completed}")

    def get_unlocked_permissions(self) -> List[str]:
        """
        Get all permissions unlocked by current rank.

        Returns:
            List of permission strings
        """
        permissions = []
        for rank_value in range(1, self.current_rank.value + 1):
            permissions.extend(RANK_DEFINITIONS[rank_value]["unlocks"])
        return permissions

    def get_next_rank_requirements(self) -> Optional[Dict]:
        """
        Get requirements for next rank.

        Returns:
            Dict of requirements, or None if at max rank
        """
        if self.current_rank == Rank.SOVEREIGN:
            return None

        next_rank = Rank(self.current_rank.value + 1)
        requirements = RANK_DEFINITIONS[next_rank.value]["requirements"]

        # Calculate progress toward each requirement
        progress = {
            "tasks_completed": {
                "current": self.metrics.tasks_completed,
                "required": requirements["tasks_completed"],
                "progress": min(1.0, self.metrics.tasks_completed / max(1, requirements["tasks_completed"]))
            },
            "success_rate": {
                "current": self.metrics.success_rate,
                "required": requirements["success_rate"],
                "progress": min(1.0, self.metrics.success_rate / max(0.01, requirements["success_rate"]))
            },
            "revenue_generated": {
                "current": self.metrics.revenue_generated,
                "required": requirements["revenue_generated"],
                "progress": 1.0 if requirements["revenue_generated"] == 0 else
                           min(1.0, self.metrics.revenue_generated / requirements["revenue_generated"])
            },
            "uptime_hours": {
                "current": self.metrics.uptime_hours,
                "required": requirements["uptime_hours"],
                "progress": min(1.0, self.metrics.uptime_hours / max(1, requirements["uptime_hours"]))
            }
        }

        return {
            "next_rank": next_rank.name,
            "requirements": progress
        }

    def get_rank_info(self, rank: Optional[Rank] = None) -> Dict:
        """
        Get information about a rank.

        Args:
            rank: Rank to get info for (default: current rank)

        Returns:
            Dict with rank details
        """
        rank = rank or self.current_rank
        definition = RANK_DEFINITIONS[rank.value]

        return {
            "rank": rank.value,
            "name": definition["name"],
            "description": definition["description"],
            "requirements": definition["requirements"],
            "unlocks": definition["unlocks"]
        }

    def get_status_summary(self) -> Dict:
        """Get comprehensive status summary."""
        return {
            "current_rank": self.current_rank.name,
            "rank_level": self.current_rank.value,
            "metrics": self.metrics.to_dict(),
            "unlocked_permissions": self.get_unlocked_permissions(),
            "next_rank_progress": self.get_next_rank_requirements(),
            "promotion_available": self.check_promotion(),
            "history_count": len(self.history)
        }


# Singleton instance
_rank_tracker: Optional[RankTracker] = None


def get_rank_tracker() -> RankTracker:
    """Get or create the singleton RankTracker."""
    global _rank_tracker
    if _rank_tracker is None:
        _rank_tracker = RankTracker()
    return _rank_tracker


if __name__ == "__main__":
    # Example usage
    tracker = RankTracker()

    print(f"\n=== AIVA Rank Status ===")
    print(f"Current Rank: {tracker.current_rank.name} (Level {tracker.current_rank.value})")
    print(f"\nMetrics:")
    print(f"  Tasks Completed: {tracker.metrics.tasks_completed}")
    print(f"  Success Rate: {tracker.metrics.success_rate:.1%}")
    print(f"  Revenue Generated: ${tracker.metrics.revenue_generated:.2f}")
    print(f"  Uptime: {tracker.metrics.uptime_hours:.1f} hours")

    print(f"\nUnlocked Permissions:")
    for perm in tracker.get_unlocked_permissions():
        print(f"  - {perm}")

    next_req = tracker.get_next_rank_requirements()
    if next_req:
        print(f"\nProgress to {next_req['next_rank']}:")
        for key, data in next_req["requirements"].items():
            print(f"  {key}: {data['current']:.1f}/{data['required']:.1f} ({data['progress']:.0%})")

    # Simulate some activity
    print("\n--- Simulating task completions ---")
    for i in range(15):
        tracker.record_task_completion(success=True, revenue=10.0)

    print(f"\nAfter simulation:")
    print(f"  Tasks: {tracker.metrics.tasks_completed}")
    print(f"  Revenue: ${tracker.metrics.revenue_generated:.2f}")
    print(f"  Promotion Available: {tracker.check_promotion()}")
