"""Data models for the learning system.

Defines courses, progress tracking, and learning history.
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from enum import Enum, auto
from typing import Dict, List, Optional, Any


class SkillType(str, Enum):
    """Types of skills agents can improve through learning."""

    ANALYSIS = "analysis"  # Technical/market analysis ability
    RISK_MANAGEMENT = "risk_management"  # Risk assessment and control
    PSYCHOLOGY = "psychology"  # Emotional control and sentiment analysis
    STRATEGY = "strategy"  # Advanced trading strategies


class CourseStatus(str, Enum):
    """Status of a course enrollment."""

    NOT_STARTED = "not_started"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    ABANDONED = "abandoned"


@dataclass
class SkillEffect:
    """Effect of completing a course on agent skills.

    Attributes:
        skill_type: Which skill to improve
        improvement: Amount to improve (0.0 to 1.0)
        unlocks_factors: List of factor names to unlock on completion
    """

    skill_type: SkillType
    improvement: float  # 0.0 to 1.0
    unlocks_factors: List[str] = field(default_factory=list)


@dataclass
class Course:
    """A learning course that agents can take.

    Attributes:
        course_id: Unique identifier for the course
        name: Human-readable course name
        description: Detailed description of course content
        duration_days: How long the course takes to complete
        cost: Cost to enroll in the course
        prerequisites: Required skill levels to enroll (skill_type -> min_level)
        effects: Skill improvements upon completion
    """

    course_id: str
    name: str
    description: str
    duration_days: int
    cost: float
    prerequisites: Dict[SkillType, float] = field(default_factory=dict)
    effects: List[SkillEffect] = field(default_factory=list)

    def can_enroll(self, skill_levels: Dict[SkillType, float]) -> bool:
        """Check if agent meets prerequisites for this course.

        Args:
            skill_levels: Current skill levels of the agent

        Returns:
            True if all prerequisites are met
        """
        for skill_type, min_level in self.prerequisites.items():
            current_level = skill_levels.get(skill_type, 0.0)
            if current_level < min_level:
                return False
        return True

    def get_missing_prerequisites(
        self, skill_levels: Dict[SkillType, float]
    ) -> Dict[SkillType, float]:
        """Get list of prerequisites that are not met.

        Args:
            skill_levels: Current skill levels of the agent

        Returns:
            Dictionary of skill_type -> required_level for unmet prerequisites
        """
        missing = {}
        for skill_type, min_level in self.prerequisites.items():
            current_level = skill_levels.get(skill_type, 0.0)
            if current_level < min_level:
                missing[skill_type] = min_level
        return missing


@dataclass
class CourseProgress:
    """Tracks an agent's progress through a specific course.

    Attributes:
        course_id: ID of the course being taken
        agent_id: ID of the agent taking the course
        status: Current enrollment status
        start_time: When the course was started
        expected_completion: When the course should complete
        actual_completion: When the course actually completed
        progress_percent: Current progress (0.0 to 100.0)
    """

    course_id: str
    agent_id: str
    status: CourseStatus = CourseStatus.NOT_STARTED
    start_time: Optional[datetime] = None
    expected_completion: Optional[datetime] = None
    actual_completion: Optional[datetime] = None
    progress_percent: float = 0.0

    def start(self) -> None:
        """Mark the course as started."""
        self.status = CourseStatus.IN_PROGRESS
        self.start_time = datetime.now()
        self.progress_percent = 0.0

    def update_progress(self, percent: float) -> None:
        """Update the progress percentage.

        Args:
            percent: New progress value (0.0 to 100.0)
        """
        self.progress_percent = max(0.0, min(100.0, percent))
        if self.progress_percent >= 100.0:
            self.complete()

    def complete(self) -> None:
        """Mark the course as completed."""
        self.status = CourseStatus.COMPLETED
        self.progress_percent = 100.0
        self.actual_completion = datetime.now()

    def abandon(self) -> None:
        """Mark the course as abandoned."""
        self.status = CourseStatus.ABANDONED

    def is_in_progress(self) -> bool:
        """Check if course is currently in progress."""
        return self.status == CourseStatus.IN_PROGRESS

    def is_completed(self) -> bool:
        """Check if course is completed."""
        return self.status == CourseStatus.COMPLETED


@dataclass
class LearningHistory:
    """Records all learning activities for an agent.

    Attributes:
        agent_id: ID of the agent
        completed_courses: List of completed course records
        total_learning_days: Total days spent learning
        total_spent: Total amount spent on learning
        skill_improvements: Accumulated skill improvements over time
    """

    agent_id: str
    completed_courses: List[Dict[str, Any]] = field(default_factory=list)
    total_learning_days: int = 0
    total_spent: float = 0.0
    skill_improvements: Dict[SkillType, float] = field(default_factory=dict)

    def record_completion(
        self,
        course: Course,
        start_time: datetime,
        completion_time: datetime,
    ) -> None:
        """Record a completed course.

        Args:
            course: The completed course
            start_time: When the course was started
            completion_time: When the course was completed
        """
        duration = (completion_time - start_time).days

        self.completed_courses.append({
            "course_id": course.course_id,
            "course_name": course.name,
            "started": start_time.isoformat(),
            "completed": completion_time.isoformat(),
            "duration_days": duration,
            "cost": course.cost,
            "effects": [
                {
                    "skill": effect.skill_type.value,
                    "improvement": effect.improvement,
                    "unlocks": effect.unlocks_factors,
                }
                for effect in course.effects
            ],
        })

        self.total_learning_days += duration
        self.total_spent += course.cost

        # Accumulate skill improvements
        for effect in course.effects:
            current = self.skill_improvements.get(effect.skill_type, 0.0)
            self.skill_improvements[effect.skill_type] = current + effect.improvement

    def get_summary(self) -> Dict[str, Any]:
        """Get a summary of learning history.

        Returns:
            Dictionary with learning statistics
        """
        return {
            "agent_id": self.agent_id,
            "courses_completed": len(self.completed_courses),
            "total_learning_days": self.total_learning_days,
            "total_spent": self.total_spent,
            "skill_improvements": {
                skill.value: improvement
                for skill, improvement in self.skill_improvements.items()
            },
        }

    def has_completed(self, course_id: str) -> bool:
        """Check if a specific course has been completed.

        Args:
            course_id: ID of the course to check

        Returns:
            True if the course was completed
        """
        return any(
            record["course_id"] == course_id
            for record in self.completed_courses
        )
