"""Course manager for agent learning system.

Handles course enrollment, progress tracking, completion detection,
and skill updates for trading agents.
"""

from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any

from openclaw.agents.base import ActivityType, BaseAgent
from openclaw.learning.models import (
    Course,
    CourseProgress,
    CourseStatus,
    LearningHistory,
    SkillType,
)
from openclaw.learning.courses import get_course_by_id, ALL_COURSES
from openclaw.utils.logging import get_logger


class CourseManager:
    """Manages learning courses for a trading agent.

    Handles enrollment, progress tracking, and skill updates.
    Ensures agents cannot trade while learning.

    Attributes:
        agent: The agent being managed
        active_enrollments: Currently enrolled courses
        learning_history: Record of completed courses
        skill_levels: Current skill levels in each area
    """

    def __init__(self, agent: BaseAgent):
        """Initialize the course manager.

        Args:
            agent: The agent to manage learning for
        """
        self.agent = agent
        self.logger = get_logger(f"learning.{agent.agent_id}")

        # Active enrollments: course_id -> CourseProgress
        self.active_enrollments: Dict[str, CourseProgress] = {}

        # Learning history
        self.learning_history = LearningHistory(agent_id=agent.agent_id)

        # Skill levels (extends base skill_level with specific areas)
        self.skill_levels: Dict[SkillType, float] = {
            SkillType.ANALYSIS: agent.skill_level * 0.8,
            SkillType.RISK_MANAGEMENT: agent.skill_level * 0.6,
            SkillType.PSYCHOLOGY: agent.skill_level * 0.4,
            SkillType.STRATEGY: agent.skill_level * 0.3,
        }

        self.logger.info(
            f"CourseManager initialized for {agent.agent_id} "
            f"with skills: {self._skills_summary()}"
        )

    def _skills_summary(self) -> str:
        """Get a string summary of current skills."""
        return ", ".join(
            f"{skill.value}={level:.1%}"
            for skill, level in self.skill_levels.items()
        )

    def can_enroll(self, course_id: str) -> tuple[bool, str]:
        """Check if agent can enroll in a course.

        Args:
            course_id: The course to check

        Returns:
            Tuple of (can_enroll, reason)
        """
        course = get_course_by_id(course_id)
        if course is None:
            return False, f"Course '{course_id}' not found"

        # Check if already enrolled and in progress
        if course_id in self.active_enrollments:
            progress = self.active_enrollments[course_id]
            if progress.is_in_progress():
                return False, f"Already enrolled in '{course.name}'"

        # Check if already completed
        if self.learning_history.has_completed(course_id):
            return False, f"Already completed '{course.name}'"

        # Check prerequisites
        if not course.can_enroll(self.skill_levels):
            missing = course.get_missing_prerequisites(self.skill_levels)
            missing_str = ", ".join(
                f"{skill.value} ({level:.0%})" for skill, level in missing.items()
            )
            return False, f"Missing prerequisites: {missing_str}"

        # Check affordability
        if not self.agent.can_afford(course.cost):
            return False, f"Cannot afford ${course.cost:,.2f}"

        return True, "OK"

    def enroll(self, course_id: str) -> tuple[bool, str]:
        """Enroll the agent in a course.

        Args:
            course_id: The course to enroll in

        Returns:
            Tuple of (success, message)
        """
        can_enroll, reason = self.can_enroll(course_id)
        if not can_enroll:
            return False, reason

        course = get_course_by_id(course_id)
        if course is None:
            return False, f"Course '{course_id}' not found"

        # Deduct cost via tracker (ensures balance history and validation)
        if not self.agent.economic_tracker.deduct(course.cost, f"Enroll: {course.name}"):
            return False, f"Insufficient balance: need ${course.cost:,.2f}"

        # Create progress tracking
        progress = CourseProgress(
            course_id=course_id,
            agent_id=self.agent.agent_id,
            status=CourseStatus.NOT_STARTED,
        )
        progress.start()
        progress.expected_completion = datetime.now() + timedelta(
            days=course.duration_days
        )

        self.active_enrollments[course_id] = progress

        # Update agent state to indicate learning (cannot trade while learning)
        self.agent.state.current_activity = ActivityType.LEARN
        self.agent.state.learning_until = progress.expected_completion

        self.logger.info(
            f"Enrolled in '{course.name}' (${course.cost:,.2f}), "
            f"duration: {course.duration_days} days, "
            f"completes: {progress.expected_completion.isoformat()}"
        )

        # Trigger event
        self.agent._trigger_event("on_learn", course_id=course_id)

        return True, f"Enrolled in '{course.name}'"

    def is_learning(self) -> bool:
        """Check if agent is currently learning (cannot trade).

        Returns:
            True if any course is in progress
        """
        for progress in self.active_enrollments.values():
            if progress.is_in_progress():
                return True
        return False

    def get_current_learning(self) -> Optional[CourseProgress]:
        """Get the currently active course progress.

        Returns:
            Active CourseProgress or None
        """
        for progress in self.active_enrollments.values():
            if progress.is_in_progress():
                return progress
        return None

    def update_progress(self, course_id: str, percent: float) -> None:
        """Update progress for a course.

        Args:
            course_id: The course to update
            percent: New progress percentage (0-100)
        """
        if course_id not in self.active_enrollments:
            self.logger.warning(f"Not enrolled in course '{course_id}'")
            return

        progress = self.active_enrollments[course_id]
        progress.update_progress(percent)

        self.logger.debug(
            f"Course '{course_id}' progress: {progress.progress_percent:.1f}%"
        )

    def check_completion(self, course_id: str) -> bool:
        """Check if a course should be completed.

        Completes the course if expected_completion time has passed.

        Args:
            course_id: The course to check

        Returns:
            True if course was completed
        """
        if course_id not in self.active_enrollments:
            return False

        progress = self.active_enrollments[course_id]
        if not progress.is_in_progress():
            return False

        course = get_course_by_id(course_id)
        if course is None:
            return False

        # Check if course duration has passed
        if progress.expected_completion and datetime.now() >= progress.expected_completion:
            self._complete_course(course_id)
            return True

        return False

    def _complete_course(self, course_id: str) -> None:
        """Complete a course and apply effects.

        Args:
            course_id: The course to complete
        """
        progress = self.active_enrollments[course_id]
        course = get_course_by_id(course_id)
        if course is None:
            return

        # Mark progress complete
        progress.complete()

        # Record in history
        self.learning_history.record_completion(
            course=course,
            start_time=progress.start_time or datetime.now(),
            completion_time=progress.actual_completion or datetime.now(),
        )

        # Apply skill improvements
        for effect in course.effects:
            current = self.skill_levels.get(effect.skill_type, 0.0)
            new_level = min(1.0, current + effect.improvement)
            self.skill_levels[effect.skill_type] = new_level

            # Update agent's general skill level (weighted average)
            self._update_agent_skill_level()

            self.logger.info(
                f"Skill improved: {effect.skill_type.value} "
                f"{current:.1%} -> {new_level:.1%}"
            )

            # Unlock factors
            for factor_name in effect.unlocks_factors:
                if factor_name not in self.agent.state.unlocked_factors:
                    self.agent.state.unlocked_factors.append(factor_name)
                    self.logger.info(f"Unlocked factor: {factor_name}")

        # Clear agent's learning state
        self.agent.state.current_activity = None
        self.agent.state.learning_until = None

        self.logger.info(
            f"Completed course '{course.name}' - "
            f"Skills: {self._skills_summary()}"
        )

    def _update_agent_skill_level(self) -> None:
        """Update agent's base skill level based on specific skills."""
        # Weighted average of specific skills
        weights = {
            SkillType.ANALYSIS: 0.3,
            SkillType.RISK_MANAGEMENT: 0.3,
            SkillType.PSYCHOLOGY: 0.2,
            SkillType.STRATEGY: 0.2,
        }

        weighted_sum = sum(
            self.skill_levels.get(skill, 0.0) * weight
            for skill, weight in weights.items()
        )

        self.agent.state.skill_level = min(1.0, max(
            self.agent.state.skill_level,
            weighted_sum
        ))

    def tick(self) -> List[str]:
        """Update learning state - call periodically (e.g., each day).

        Checks for course completions and updates progress.

        Returns:
            List of completed course IDs
        """
        completed = []
        for course_id in list(self.active_enrollments.keys()):
            if self.check_completion(course_id):
                completed.append(course_id)
        return completed

    def abandon_course(self, course_id: str) -> bool:
        """Abandon an in-progress course.

        Args:
            course_id: The course to abandon

        Returns:
            True if abandoned successfully
        """
        if course_id not in self.active_enrollments:
            return False

        progress = self.active_enrollments[course_id]
        if not progress.is_in_progress():
            return False

        progress.abandon()

        # Clear agent's learning state
        self.agent.state.current_activity = None
        self.agent.state.learning_until = None

        self.logger.warning(f"Abandoned course '{course_id}'")
        return True

    def get_available_courses(self) -> List[Course]:
        """Get list of courses the agent can currently enroll in.

        Returns:
            List of available courses
        """
        completed = [
            record["course_id"]
            for record in self.learning_history.completed_courses
        ]

        available = []
        for course in ALL_COURSES:
            if course.course_id in completed:
                continue
            if course.course_id in self.active_enrollments:
                continue
            if course.can_enroll(self.skill_levels):
                available.append(course)

        return available

    def get_learning_status(self) -> Dict[str, Any]:
        """Get complete learning status for the agent.

        Returns:
            Dictionary with learning status
        """
        current = self.get_current_learning()
        current_course = None
        if current:
            course = get_course_by_id(current.course_id)
            current_course = {
                "course_id": current.course_id,
                "course_name": course.name if course else current.course_id,
                "progress_percent": current.progress_percent,
                "expected_completion": current.expected_completion.isoformat()
                if current.expected_completion
                else None,
                "days_remaining": (
                    current.expected_completion - datetime.now()
                ).days
                if current.expected_completion
                else None,
            }

        return {
            "agent_id": self.agent.agent_id,
            "is_learning": self.is_learning(),
            "current_course": current_course,
            "skills": {
                skill.value: round(level, 4)
                for skill, level in self.skill_levels.items()
            },
            "history": self.learning_history.get_summary(),
            "available_courses": [
                {
                    "course_id": c.course_id,
                    "name": c.name,
                    "cost": c.cost,
                    "duration_days": c.duration_days,
                }
                for c in self.get_available_courses()
            ],
        }
