"""Goal Manager for tracking project goals and success metrics."""
import json
from datetime import datetime
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict
import logging

logger = logging.getLogger(__name__)

@dataclass
class Goal:
    """Represents a project goal with success metrics."""
    id: str
    description: str
    success_criteria: List[str]
    metrics: Dict[str, Any]
    priority: int
    status: str
    created_at: str
    updated_at: str
    completed_at: Optional[str] = None

@dataclass
class Metric:
    """Represents a measurable metric for goal evaluation."""
    name: str
    value: Any
    target: Any
    unit: str
    timestamp: str
    status: str

class GoalManager:
    """Manages project goals and success metrics."""
    
    def __init__(self, context_manager):
        """Initialize the Goal Manager."""
        self.context_manager = context_manager
        self.goals: Dict[str, Goal] = {}
        self.metrics: Dict[str, List[Metric]] = {}
        self.load_goals()

    def load_goals(self):
        """Load goals from the context database."""
        context = self.context_manager.get_project_context()
        for goal_dict in context.goals:
            goal = Goal(**goal_dict)
            self.goals[goal.id] = goal

    def save_goals(self):
        """Save goals to the context database."""
        self.context_manager.update_project_context({
            'goals': [asdict(goal) for goal in self.goals.values()]
        })

    def add_goal(self, description: str, success_criteria: List[str], 
                 metrics: Dict[str, Any], priority: int = 1) -> Goal:
        """Add a new project goal."""
        goal_id = f"goal_{len(self.goals) + 1}"
        now = datetime.now().isoformat()
        
        goal = Goal(
            id=goal_id,
            description=description,
            success_criteria=success_criteria,
            metrics=metrics,
            priority=priority,
            status="active",
            created_at=now,
            updated_at=now
        )
        
        self.goals[goal_id] = goal
        self.save_goals()
        
        logger.info(f"Added new goal: {description}")
        return goal

    def update_goal(self, goal_id: str, updates: Dict[str, Any]) -> Goal:
        """Update an existing goal."""
        if goal_id not in self.goals:
            raise ValueError(f"Goal {goal_id} not found")
            
        goal = self.goals[goal_id]
        goal_dict = asdict(goal)
        
        for key, value in updates.items():
            if key in goal_dict:
                goal_dict[key] = value
        
        goal_dict['updated_at'] = datetime.now().isoformat()
        self.goals[goal_id] = Goal(**goal_dict)
        self.save_goals()
        
        return self.goals[goal_id]

    def record_metric(self, goal_id: str, name: str, value: Any, 
                     target: Any, unit: str) -> Metric:
        """Record a new metric measurement."""
        if goal_id not in self.goals:
            raise ValueError(f"Goal {goal_id} not found")
            
        status = self._evaluate_metric(value, target)
        metric = Metric(
            name=name,
            value=value,
            target=target,
            unit=unit,
            timestamp=datetime.now().isoformat(),
            status=status
        )
        
        if goal_id not in self.metrics:
            self.metrics[goal_id] = []
        self.metrics[goal_id].append(metric)
        
        self._update_goal_status(goal_id)
        return metric

    def get_goal(self, goal_id: str) -> Optional[Goal]:
        """Get a specific goal by ID."""
        return self.goals.get(goal_id)

    def get_active_goals(self) -> List[Goal]:
        """Get all active goals."""
        return [goal for goal in self.goals.values() 
                if goal.status == "active"]

    def get_completed_goals(self) -> List[Goal]:
        """Get all completed goals."""
        return [goal for goal in self.goals.values() 
                if goal.status == "completed"]

    def get_goal_metrics(self, goal_id: str) -> List[Metric]:
        """Get all metrics for a specific goal."""
        return self.metrics.get(goal_id, [])

    def evaluate_progress(self) -> Dict[str, Any]:
        """Evaluate overall progress towards goals."""
        total_goals = len(self.goals)
        completed_goals = len(self.get_completed_goals())
        active_goals = len(self.get_active_goals())
        
        metrics_summary = {}
        for goal_id, metrics in self.metrics.items():
            if metrics:
                latest_metric = metrics[-1]
                metrics_summary[goal_id] = {
                    'name': latest_metric.name,
                    'value': latest_metric.value,
                    'target': latest_metric.target,
                    'status': latest_metric.status
                }
        
        return {
            'total_goals': total_goals,
            'completed_goals': completed_goals,
            'active_goals': active_goals,
            'completion_rate': completed_goals / total_goals if total_goals > 0 else 0,
            'metrics_summary': metrics_summary
        }

    def _evaluate_metric(self, value: Any, target: Any) -> str:
        """Evaluate a metric value against its target."""
        try:
            if isinstance(value, (int, float)) and isinstance(target, (int, float)):
                if value >= target:
                    return "achieved"
                elif value >= 0.8 * target:
                    return "near_target"
                else:
                    return "below_target"
            elif value == target:
                return "achieved"
            else:
                return "in_progress"
        except Exception as e:
            logger.error(f"Error evaluating metric: {e}")
            return "error"

    def _update_goal_status(self, goal_id: str):
        """Update goal status based on metrics."""
        goal = self.goals[goal_id]
        metrics = self.metrics.get(goal_id, [])
        
        if not metrics:
            return
            
        # Check if all recent metrics are achieved
        recent_metrics = metrics[-len(goal.metrics):]
        all_achieved = all(m.status == "achieved" for m in recent_metrics)
        
        if all_achieved and goal.status != "completed":
            self.update_goal(goal_id, {
                'status': "completed",
                'completed_at': datetime.now().isoformat()
            })
            logger.info(f"Goal {goal_id} completed: {goal.description}")
            
            # Add insight about goal completion
            self.context_manager.add_insight(
                f"Goal completed: {goal.description}",
                'goal_achievement',
                'goal_manager'
            ) 