"""
Core agent implementation that coordinates all components
"""
from typing import Optional, Dict, List, Any
from src.workspace.manager import WorkspaceManager
from src.llm.llm_interface import LLMInterface
from src.tasks.task_manager import TaskManager
from src.terminal.terminal_manager import TerminalManager
from src.chat.interface import ChatInterface, Response, ResponseType
from src.chat.response_handler import ResponseHandler
import asyncio
import json
from datetime import datetime

class CodingAgent:
    def __init__(
        self,
        workspace_path: str,
        api_key: str,
        model: str = "gpt-4"
    ):
        # Initialize components
        self.workspace = WorkspaceManager(workspace_path)
        self.llm = LLMInterface(api_key, model)
        self.task_manager = TaskManager(workspace_path)
        self.terminal = TerminalManager(workspace_path)
        
        # Initialize chat interface
        self.chat = ChatInterface(api_key, model)
        
        # Initialize response handler
        self.response_handler = ResponseHandler(
            workspace=self.workspace,
            terminal=self.terminal
        )
        
        # Create initial chat session
        self.chat.create_session()
        
    async def run(self):
        """Main agent loop"""
        while True:
            # 1. Analyze workspace for context
            context = self.workspace.get_context()
            
            # 2. Get next task from task manager
            current_task = self.task_manager.get_next_task()
            if not current_task:
                break
                
            # 3. Generate solution using LLM
            solution = await self.llm.generate_solution(
                task=current_task,
                context=context
            )
            
            # 4. Execute solution
            success = await self._execute_solution(current_task, solution)
            
            # 5. Update task status
            if success:
                self.task_manager.mark_complete(current_task)
            else:
                self.task_manager.mark_failed(current_task)
                
    async def _execute_solution(self, task: str, solution: Dict[str, Any]) -> bool:
        """Execute a solution, handling both code changes and terminal commands"""
        try:
            # Handle code changes
            if "code_changes" in solution:
                for change in solution["code_changes"]:
                    # Apply code changes using workspace manager
                    await self.workspace.apply_change(change)
                    
            # Handle terminal commands
            if "commands" in solution:
                for cmd_info in solution["commands"]:
                    # Extract command and any expected patterns
                    command = cmd_info["command"]
                    patterns = []
                    
                    if "expected_output" in cmd_info:
                        for pattern_info in cmd_info["expected_output"]:
                            pattern = OutputPattern(
                                pattern=pattern_info["pattern"],
                                is_regex=pattern_info.get("is_regex", False),
                                response=pattern_info.get("response"),
                                should_terminate=pattern_info.get("should_terminate", False)
                            )
                            patterns.append(pattern)
                            
                    # Execute command with patterns
                    result = await self.terminal.execute_command(
                        command=command,
                        expected_patterns=patterns if patterns else None
                    )
                    
                    # Analyze result
                    analysis = self.terminal.analyze_output(result)
                    
                    # If command failed, let LLM analyze the error
                    if result.status != CommandStatus.SUCCESS:
                        error_solution = await self.llm.analyze_error(
                            command=command,
                            error_output=result.error,
                            context=self.workspace.get_context()
                        )
                        
                        # Try to handle the error
                        if "fix_command" in error_solution:
                            # Try the suggested fix
                            retry_result = await self.terminal.execute_command(
                                error_solution["fix_command"]
                            )
                            if retry_result.status != CommandStatus.SUCCESS:
                                return False
                                
            # Handle tests
            if "tests" in solution:
                for test in solution["tests"]:
                    test_result = await self.terminal.execute_command(test)
                    if test_result.status != CommandStatus.SUCCESS:
                        return False
                        
            return True
            
        except Exception as e:
            self.task_manager.mark_failed(task, str(e))
            return False
