"""
AIVA Strategic Objectives Loader - PM-023

Loads and manages AIVA's tiered strategic objectives.
Objectives organized in 4 tiers reflecting priority and capability progression.
"""

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 ObjectiveTier(Enum):
    """Strategic objective tiers in priority order."""
    TIER_1 = 1  # Foundation: Memory excellence, infrastructure stability
    TIER_2 = 2  # Growth: Skill development, cross-agent coordination
    TIER_3 = 3  # Autonomy: Independent decision-making
    TIER_4 = 4  # Impact: Revenue generation


class ObjectiveStatus(Enum):
    """Status of an objective."""
    NOT_STARTED = "not_started"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    BLOCKED = "blocked"
    DEFERRED = "deferred"


@dataclass
class Objective:
    """Represents a strategic objective."""
    objective_id: str
    tier: ObjectiveTier
    name: str
    description: str
    success_criteria: List[str]
    status: ObjectiveStatus = ObjectiveStatus.NOT_STARTED
    progress_percent: float = 0.0
    dependencies: List[str] = field(default_factory=list)
    created_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())
    updated_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())
    completed_at: Optional[str] = None
    metadata: Dict = field(default_factory=dict)

    def to_dict(self) -> Dict:
        """Convert to dictionary."""
        data = asdict(self)
        data["tier"] = self.tier.value
        data["status"] = self.status.value
        return data

    @classmethod
    def from_dict(cls, data: Dict) -> "Objective":
        """Create from dictionary."""
        data["tier"] = ObjectiveTier(data["tier"])
        data["status"] = ObjectiveStatus(data["status"])
        return cls(**data)


# Default strategic objectives per tier
DEFAULT_OBJECTIVES: Dict[int, List[Dict]] = {
    1: [
        {
            "objective_id": "T1-001",
            "name": "Memory Excellence",
            "description": "Achieve reliable, accurate memory recall and storage across all backends",
            "success_criteria": [
                "Memory queries return relevant results >95% of time",
                "Memory storage succeeds >99% of attempts",
                "Cross-backend consistency maintained",
                "Memory latency <500ms for queries"
            ]
        },
        {
            "objective_id": "T1-002",
            "name": "Infrastructure Stability",
            "description": "Ensure Genesis infrastructure runs reliably 24/7",
            "success_criteria": [
                "System uptime >99.5%",
                "No critical errors in 24-hour window",
                "All health checks pass consistently",
                "Resource usage within defined limits"
            ]
        },
        {
            "objective_id": "T1-003",
            "name": "Validation Pipeline",
            "description": "Implement robust 3-gate validation for all outputs",
            "success_criteria": [
                "All outputs pass syntax validation",
                "Quality gate catches >90% of low-quality outputs",
                "Safety gate prevents all dangerous actions",
                "Validation latency <100ms"
            ]
        }
    ],
    2: [
        {
            "objective_id": "T2-001",
            "name": "Skill Development",
            "description": "Build and refine autonomous skill execution capabilities",
            "success_criteria": [
                "Successfully execute all registered skills",
                "Create new skills from learned patterns",
                "Skill success rate >90%",
                "Skill execution logged and auditable"
            ]
        },
        {
            "objective_id": "T2-002",
            "name": "Cross-Agent Coordination",
            "description": "Effectively coordinate with Claude Code and other agents",
            "success_criteria": [
                "Successful handoffs between agents",
                "Context preserved across agent boundaries",
                "Parallel task execution when appropriate",
                "Clear escalation paths defined"
            ]
        },
        {
            "objective_id": "T2-003",
            "name": "Knowledge Integration",
            "description": "Continuously learn and integrate new knowledge",
            "success_criteria": [
                "New documents ingested within 5 minutes",
                "Entity extraction accuracy >85%",
                "Knowledge graph relationships accurate",
                "Learnings reflected in future decisions"
            ]
        }
    ],
    3: [
        {
            "objective_id": "T3-001",
            "name": "Independent Decision-Making",
            "description": "Make autonomous decisions within defined boundaries",
            "success_criteria": [
                "Correctly classify action risk levels",
                "Execute low-risk decisions autonomously",
                "Escalate appropriately for high-risk decisions",
                "Decision reasoning logged and explainable"
            ]
        },
        {
            "objective_id": "T3-002",
            "name": "Strategic Planning",
            "description": "Develop and execute strategic plans",
            "success_criteria": [
                "Generate actionable task breakdowns",
                "Prioritize tasks based on objectives",
                "Adapt plans based on outcomes",
                "Track progress toward objectives"
            ]
        },
        {
            "objective_id": "T3-003",
            "name": "Self-Improvement",
            "description": "Identify and implement self-improvement opportunities",
            "success_criteria": [
                "Identify performance bottlenecks",
                "Propose process improvements",
                "Learn from failures and successes",
                "Measure improvement over time"
            ]
        }
    ],
    4: [
        {
            "objective_id": "T4-001",
            "name": "Revenue Generation",
            "description": "Contribute directly to revenue through automated actions",
            "success_criteria": [
                "Execute revenue-generating workflows",
                "Track revenue attribution accurately",
                "Optimize conversion funnels",
                "Generate positive ROI on API costs"
            ]
        },
        {
            "objective_id": "T4-002",
            "name": "Client Value Delivery",
            "description": "Deliver measurable value to clients",
            "success_criteria": [
                "Automate client-facing processes",
                "Reduce manual intervention requirements",
                "Improve client satisfaction metrics",
                "Scale services efficiently"
            ]
        },
        {
            "objective_id": "T4-003",
            "name": "Business Intelligence",
            "description": "Provide actionable business insights",
            "success_criteria": [
                "Generate accurate analytics reports",
                "Identify growth opportunities",
                "Predict market trends",
                "Inform strategic decisions"
            ]
        }
    ]
}


class StrategicObjectivesLoader:
    """
    Loads and manages AIVA's strategic objectives.

    Usage:
        loader = StrategicObjectivesLoader()
        objectives = loader.load_objectives()
        tier1 = loader.get_tier_objectives(ObjectiveTier.TIER_1)
    """

    def __init__(self, config_path: Optional[str] = None):
        """
        Initialize the objectives loader.

        Args:
            config_path: Path to custom objectives JSON file
        """
        self.config_path = config_path
        self.objectives: Dict[str, Objective] = {}
        self._loaded = False
        logger.info("StrategicObjectivesLoader initialized")

    def load_objectives(self) -> Dict[str, Objective]:
        """
        Load strategic objectives from config or defaults.

        Returns:
            Dict mapping objective_id to Objective
        """
        if self._loaded:
            return self.objectives

        # Try to load from config file
        if self.config_path and os.path.exists(self.config_path):
            logger.info(f"Loading objectives from {self.config_path}")
            with open(self.config_path, "r") as f:
                config_data = json.load(f)
            self._parse_config(config_data)
        else:
            # Use default objectives
            logger.info("Loading default strategic objectives")
            self._load_defaults()

        self._loaded = True
        logger.info(f"Loaded {len(self.objectives)} objectives")
        return self.objectives

    def _load_defaults(self) -> None:
        """Load default objectives."""
        for tier_num, objectives in DEFAULT_OBJECTIVES.items():
            tier = ObjectiveTier(tier_num)
            for obj_data in objectives:
                objective = Objective(
                    objective_id=obj_data["objective_id"],
                    tier=tier,
                    name=obj_data["name"],
                    description=obj_data["description"],
                    success_criteria=obj_data["success_criteria"]
                )
                self.objectives[objective.objective_id] = objective

    def _parse_config(self, config_data: Dict) -> None:
        """Parse config file data into objectives."""
        for obj_data in config_data.get("objectives", []):
            objective = Objective.from_dict(obj_data)
            self.objectives[objective.objective_id] = objective

    def get_tier_objectives(self, tier: ObjectiveTier) -> List[Objective]:
        """
        Get all objectives for a specific tier.

        Args:
            tier: The tier to filter by

        Returns:
            List of objectives in that tier
        """
        return [obj for obj in self.objectives.values() if obj.tier == tier]

    def get_active_objectives(self) -> List[Objective]:
        """Get all non-completed objectives."""
        return [
            obj for obj in self.objectives.values()
            if obj.status not in [ObjectiveStatus.COMPLETED, ObjectiveStatus.DEFERRED]
        ]

    def get_objective(self, objective_id: str) -> Optional[Objective]:
        """Get a specific objective by ID."""
        return self.objectives.get(objective_id)

    def update_objective_status(
        self,
        objective_id: str,
        status: ObjectiveStatus,
        progress: Optional[float] = None
    ) -> bool:
        """
        Update an objective's status.

        Args:
            objective_id: ID of objective to update
            status: New status
            progress: Optional progress percentage (0-100)

        Returns:
            True if update successful
        """
        if objective_id not in self.objectives:
            logger.warning(f"Objective not found: {objective_id}")
            return False

        objective = self.objectives[objective_id]
        objective.status = status
        objective.updated_at = datetime.utcnow().isoformat()

        if progress is not None:
            objective.progress_percent = min(100.0, max(0.0, progress))

        if status == ObjectiveStatus.COMPLETED:
            objective.completed_at = datetime.utcnow().isoformat()
            objective.progress_percent = 100.0

        logger.info(f"Updated objective {objective_id}: status={status.value}")
        return True

    def get_next_priority_objective(self) -> Optional[Objective]:
        """
        Get the highest priority objective to work on.

        Priority order:
        1. Lower tier first
        2. In-progress over not-started
        3. Higher progress percentage
        """
        active = self.get_active_objectives()
        if not active:
            return None

        # Sort by tier, then status, then progress
        def priority_key(obj: Objective):
            status_order = {
                ObjectiveStatus.IN_PROGRESS: 0,
                ObjectiveStatus.NOT_STARTED: 1,
                ObjectiveStatus.BLOCKED: 2
            }
            return (
                obj.tier.value,
                status_order.get(obj.status, 3),
                -obj.progress_percent
            )

        sorted_objectives = sorted(active, key=priority_key)
        return sorted_objectives[0] if sorted_objectives else None

    def save_state(self, path: str) -> bool:
        """
        Save current objectives state to file.

        Args:
            path: Path to save state

        Returns:
            True if save successful
        """
        try:
            state = {
                "saved_at": datetime.utcnow().isoformat(),
                "objectives": [obj.to_dict() for obj in self.objectives.values()]
            }
            with open(path, "w") as f:
                json.dump(state, f, indent=2)
            logger.info(f"Saved objectives state to {path}")
            return True
        except Exception as e:
            logger.error(f"Failed to save objectives: {e}")
            return False

    def get_tier_summary(self) -> Dict[int, Dict]:
        """Get summary statistics per tier."""
        summary = {}
        for tier in ObjectiveTier:
            tier_objs = self.get_tier_objectives(tier)
            if tier_objs:
                completed = sum(1 for o in tier_objs if o.status == ObjectiveStatus.COMPLETED)
                in_progress = sum(1 for o in tier_objs if o.status == ObjectiveStatus.IN_PROGRESS)
                avg_progress = sum(o.progress_percent for o in tier_objs) / len(tier_objs)
                summary[tier.value] = {
                    "total": len(tier_objs),
                    "completed": completed,
                    "in_progress": in_progress,
                    "avg_progress": round(avg_progress, 1)
                }
        return summary


# Singleton instance
_objectives_loader: Optional[StrategicObjectivesLoader] = None


def load_objectives() -> Dict[str, Objective]:
    """Load objectives using singleton loader."""
    global _objectives_loader
    if _objectives_loader is None:
        _objectives_loader = StrategicObjectivesLoader()
    return _objectives_loader.load_objectives()


def get_objectives_loader() -> StrategicObjectivesLoader:
    """Get the singleton objectives loader."""
    global _objectives_loader
    if _objectives_loader is None:
        _objectives_loader = StrategicObjectivesLoader()
        _objectives_loader.load_objectives()
    return _objectives_loader


if __name__ == "__main__":
    # Example usage
    loader = StrategicObjectivesLoader()
    objectives = loader.load_objectives()

    print("\n=== Strategic Objectives Summary ===\n")

    for tier in ObjectiveTier:
        tier_objs = loader.get_tier_objectives(tier)
        print(f"TIER {tier.value}: {tier.name}")
        for obj in tier_objs:
            print(f"  [{obj.objective_id}] {obj.name}")
            print(f"      Status: {obj.status.value} | Progress: {obj.progress_percent}%")
        print()

    # Get next priority
    next_obj = loader.get_next_priority_objective()
    if next_obj:
        print(f"Next priority: [{next_obj.objective_id}] {next_obj.name}")

    # Get summary
    summary = loader.get_tier_summary()
    print(f"\nTier Summary: {summary}")
