import logging
from kogniterm.utils.logger import setup_logger
setup_logger() # Initialize root logger early
import sys
import os
import argparse
from dotenv import load_dotenv # Importar load_dotenv
from prompt_toolkit.completion import Completer, Completion
from rich.text import Text
from rich.syntax import Syntax
import re

load_dotenv() # Cargar variables de entorno al inicio

# New helper function
def _format_text_with_basic_markdown(text: str) -> Text:
    """Applies basic Markdown-like formatting to a string using rich.Text."""
    formatted_text = Text()
    
    lines = text.split('\n')
    
    in_code_block = False
    code_block_lang = ""
    code_block_content = []

    for line in lines:
        code_block_match = re.match(r"```(\w*)", line)
        if code_block_match:
            if in_code_block: # End of code block
                in_code_block = False
                if code_block_content:
                    code_str = "\n".join(code_block_content)
                    lexer = code_block_lang if code_block_lang else "plaintext"
                    formatted_text.append(Text.from_ansi(str(Syntax(code_str, lexer, theme="monokai", line_numbers=False))))
                    code_block_content = []
                formatted_text.append("\n")
            else: # Start of code block
                in_code_block = True
                code_block_lang = code_block_match.group(1) if code_block_match.group(1) else ""
                formatted_text.append("\n")
        elif in_code_block:
            code_block_content.append(line)
        else:
            # Apply inline formatting (bold)
            parts = re.split(r"(\*\*.*?\*\*)", line)
            for part in parts:
                if part.startswith('**') and part.endswith('**'):
                    formatted_text.append(part[2:-2], style="bold")
                else:
                    formatted_text.append(part)
            formatted_text.append("\n")

    if in_code_block and code_block_content:
        code_str = "\n".join(code_block_content)
        lexer = code_block_lang if code_block_lang else "plaintext"
        formatted_text.append(Text.from_ansi(str(Syntax(code_str, lexer, theme="monokai", line_numbers=False))))

    return formatted_text

# --- Importar KogniTermApp ---
from kogniterm.terminal.kogniterm_app import KogniTermApp
from kogniterm.terminal.tui.tui_app import KogniTermTUI
from kogniterm.core.llm_service import LLMService
from kogniterm.core.command_executor import CommandExecutor # Importar CommandExecutor
from kogniterm.core.agent_state import AgentState # Importar AgentState
import os
from rich.text import Text
from rich.syntax import Syntax
from rich.console import Console
from rich.padding import Padding
from rich.live import Live
from rich.markdown import Markdown
from rich.status import Status
import json
import asyncio
import re
import sys
import os
import asyncio
import threading # Importar threading para el watcher

from kogniterm.terminal.agent_interaction_manager import AgentInteractionManager
from kogniterm.terminal.command_approval_handler import CommandApprovalHandler
from kogniterm.terminal.meta_command_processor import MetaCommandProcessor
from kogniterm.terminal.terminal_ui import TerminalUI
from kogniterm.terminal.cli import run_cli

logger = logging.getLogger("kogniterm.terminal")

console = Console()







import signal

async def _main_async():
    """Función principal asíncrona para iniciar la terminal de KogniTerm."""
    from kogniterm.terminal.config_manager import ConfigManager
    from kogniterm.terminal.themes import set_kogniterm_theme
    
    # Cargar configuración y aplicar tema guardado antes de iniciar nada
    config_manager = ConfigManager()
    saved_theme = config_manager.get_config("theme")
    if saved_theme:
        try:
            set_kogniterm_theme(saved_theme)
        except ValueError:
            # Si el tema guardado ya no es válido, se mantiene el default
            pass

    auto_approve = '-y' in sys.argv or '--yes' in sys.argv
    
    # Obtener el directorio de trabajo actual
    workspace_directory = os.getcwd()

    # --- INYECCIÓN DE CONFIGURACIÓN DE MODELO ---
    # Leer el modelo configurado por el usuario y establecerlo en las variables de entorno
    # ANTES de importar LLMService, ya que este lee os.environ al nivel de módulo.
    default_model = config_manager.get_config("default_model")
    if default_model:
        # Solo sobrescribir si no se pasó explícitamente por variable de entorno en esta ejecución
        # Esto permite overrides temporales: LITELLM_MODEL=foo kogniterm
        if "LITELLM_MODEL" not in os.environ:
            os.environ["LITELLM_MODEL"] = default_model
            # print(f"ℹ️  Using configured model: {default_model}")

    # --- INYECCIÓN DE API KEYS ---
    # Mapeo de proveedores a variables de entorno
    api_key_mapping = {
        "openrouter": "OPENROUTER_API_KEY",
        "google": "GOOGLE_API_KEY",
        "openai": "OPENAI_API_KEY",
        "anthropic": "ANTHROPIC_API_KEY",
        "cohere": "COHERE_API_KEY",
        "zhipuai": "ZHIPUAI_API_KEY",
        "ollama_cloud": "OLLAMA_CLOUD_API_KEY",
        "litellm": "LITELLM_API_KEY"
    }
    
    for provider, env_var in api_key_mapping.items():
        # Solo inyectar si no existe ya en el entorno (prioridad a variables explícitas)
        if env_var not in os.environ:
            saved_key = config_manager.get_config(f"api_key_{provider}")
            if saved_key:
                os.environ[env_var] = saved_key

    llm_service_instance = LLMService() # Usar el project_context inicializado
    command_executor_instance = CommandExecutor() # Inicializar CommandExecutor
    agent_state_instance = AgentState(messages=llm_service_instance.conversation_history) # Inicializar AgentState
    llm_service_instance.skill_manager.set_agent_state(agent_state_instance) # Vincular estado del agente a las herramientas

    app = KogniTermTUI(
        llm_service=llm_service_instance,
        command_executor=command_executor_instance,
        agent_state=agent_state_instance,
        workspace_directory=workspace_directory
    )

    # Configurar manejador de señales para Ctrl+C
    def signal_handler(sig, frame):
        # Enviar señal de interrupción a la cola de la app
        if app and app.terminal_ui:
            app.terminal_ui.get_interrupt_queue().put_nowait(True)
            # También establecer la bandera directamente en el servicio LLM por si acaso
            if app.llm_service:
                app.llm_service.stop_generation_flag = True
        # No salimos de la app, solo interrumpimos la tarea actual

        # Configurar en Textual en su lugar
        pass

    # No llamamos a signal.signal con SIGINT cuando usamos TUI porque Textual maneja señales.
    # signal.signal(signal.SIGINT, signal_handler)
    
    try:
        await app.run_async() # Textual App run inside an existing asyncio event loop
    finally:
        # Cerrar el servicio LLM y liberar recursos (como ChromaDB)
        if hasattr(app, 'llm_service') and app.llm_service:
            app.llm_service.close()
            
        # Asegurarse de que el FileCompleter se limpie al salir (si fuese prompt_toolkit)
        if hasattr(app, 'prompt_session') and app.prompt_session and app.prompt_session.completer and hasattr(app.prompt_session.completer, 'dispose'):
            app.prompt_session.completer.dispose()

def run_simple_cli():
    """Run a simple CLI mode using Rich (no TUI)."""
    import asyncio
    from rich.console import Console
    from rich.panel import Panel
    from rich.align import Align
    from rich.markdown import Markdown
    from kogniterm.terminal.terminal_ui import create_welcome_banner, ColorPalette, get_random_motivational_message
    
    console = Console()
    
    # Print welcome banner
    banner_text = """
██╗  ██╗ ██████╗  ██████╗ ███╗   ██╗██╗████████╗███████╗██████╗ ███╗   ███╗
██║ ██╔╝██╔═══██╗██╔════╝ ████╗  ██║██║╚══██╔══╝██╔════╝██╔══██╗████╗ ████║
█████╔╝ ██║   ██║██║  ███╗██╔██╗ ██║██║   ██║   █████╗  ██████╔╝██╔████╔██║
██╔═██╗ ██║   ██║██║   ██║██║╚██╗██║██║   ██║   ██╔══╝  ██╔══██╗██║╚██╔╝██║
██║  ██╗╚██████╔╝╚██████╔╝██║ ╚████║██║   ██║   ███████╗██║  ██║██║ ╚═╝ ██║
╚═╝  ╚═╝ ╚═════╝  ╚═════╝ ╚═╝  ╚═══╝╚═╝   ╚═╝   ╚══════╝╚═╝  ╚═╝╚═╝     ╚═╝
"""
    banner = create_welcome_banner(
        banner_text,
        subtitle=get_random_motivational_message(),
        color=ColorPalette.PRIMARY
    )
    console.print(banner)
    
    welcome_panel = Panel(
        f"Escribe '[{ColorPalette.SUCCESS}]%salir[/{ColorPalette.SUCCESS}]' para terminar o '[{ColorPalette.SUCCESS}]%help[/{ColorPalette.SUCCESS}]' para ver los comandos.",
        title=f"[bold {ColorPalette.SUCCESS}]✨ Bienvenido (CLI Mode)[/bold {ColorPalette.SUCCESS}]",
        border_style=ColorPalette.SUCCESS,
        expand=False
    )
    console.print(Align.center(welcome_panel))
    console.print()
    
    # Initialize services for CLI
    from kogniterm.core.llm_service import LLMService
    from kogniterm.core.agents.bash_agent import AgentState, get_system_message
    from kogniterm.core.command_executor import CommandExecutor
    from kogniterm.terminal.meta_command_processor import MetaCommandProcessor
    from kogniterm.terminal.agent_interaction_manager import AgentInteractionManager
    from kogniterm.terminal.command_approval_handler import CommandApprovalHandler
    
    llm_service = LLMService()
    agent_state = AgentState()
    command_executor = CommandExecutor()
    
    # Initialize with system message
    agent_state.messages = [get_system_message(llm_service)]
    llm_service.conversation_history = [get_system_message(llm_service)]
    
    # Create a simple CLI UI class
    class SimpleCLIUI:
        def __init__(self, console):
            self.console = console
            self.is_tui = False
        
        def print_message(self, message, style=None):
            if style:
                self.console.print(f"[{style}]{message}[/{style}]")
            else:
                self.console.print(message)
        
        def print_welcome_banner(self):
            pass
        
        def print_ai_response(self, response: str, show_thinking: bool = False):
            """Print AI response in a nice panel."""
            if show_thinking and hasattr(self, '_thinking') and self._thinking:
                self.console.print(Panel(
                    f"[dim]{self._thinking}[/dim]",
                    title="🤔 Pensando...",
                    border_style="yellow",
                    expand=False
                ))
            
            if response:
                # Check if response contains markdown code blocks
                if "```" in response:
                    # Use markdown rendering for rich responses
                    md = Markdown(response)
                    self.console.print(Panel(
                        md,
                        title=f"[{ColorPalette.PRIMARY}]🤖 Respuesta[/{ColorPalette.PRIMARY}]",
                        border_style=ColorPalette.PRIMARY,
                        expand=False
                    ))
                else:
                    self.console.print(Panel(
                        response,
                        title=f"[{ColorPalette.PRIMARY}]🤖 Respuesta[/{ColorPalette.PRIMARY}]",
                        border_style=ColorPalette.PRIMARY,
                        expand=False
                    ))
        
        def print_command_output(self, command: str, output: str, exit_code: int = 0):
            """Print command output."""
            from kogniterm.terminal.visual_components import create_terminal_output_panel
            panel = create_terminal_output_panel(command, output)
            self.console.print(panel)
        
        def print_error(self, message: str):
            self.console.print(Panel(
                f"[{ColorPalette.ERROR}]{message}[/{ColorPalette.ERROR}]",
                title="❌ Error",
                border_style=ColorPalette.ERROR,
                expand=False
            ))
        
        def print_warning(self, message: str):
            self.console.print(Panel(
                f"[{ColorPalette.WARNING}]{message}[/{ColorPalette.WARNING}]",
                title="⚠️ Advertencia",
                border_style=ColorPalette.WARNING,
                expand=False
            ))
        
        def get_interrupt_queue(self):
            return None
        
        def clear_chat(self):
            pass
        
        def set_terminal_cursor(self, active: bool, executor=None):
            """Not supported in CLI mode."""
            pass
        
        def is_tui(self) -> bool:
            return False
    
    cli_ui = SimpleCLIUI(console)
    
    # Setup command approval handler
    command_approval_handler = CommandApprovalHandler(
        llm_service,
        command_executor,
        None,
        cli_ui,
        agent_state,
        llm_service.get_tool("file_update"),
        llm_service.get_tool("advanced_file_editor"),
        llm_service.get_tool("file_operations")
    )
    
    # Setup agent interaction manager
    agent_interaction_manager = AgentInteractionManager(
        llm_service,
        agent_state,
        cli_ui,
        None,
        command_approval_handler
    )
    
    # Meta command processor
    meta_processor = MetaCommandProcessor(llm_service, agent_state, cli_ui, None)
    meta_processor.kogniterm_app = None
    
    # Simple input loop with full LLM support
    while True:
        try:
            user_input = console.input("\n[bold cyan]>[/bold cyan] ")
            if not user_input.strip():
                continue
            
            if user_input.strip().lower() in ['%salir', 'salir', 'exit']:
                console.print("[green]¡Hasta luego! 👋[/green]")
                break
            
            # Show user message
            cli_ui.print_message(f"[bold]{user_input}[/bold]", style="dim")
            
            # Process meta commands first
            is_meta = asyncio.run(meta_processor.process_meta_command(user_input))
            if is_meta:
                continue
            
            # Process with LLM via agent interaction manager
            console.print("[yellow]⏳ Procesando...[/yellow]")
            
            try:
                final_state = agent_interaction_manager.invoke_agent(user_input)
                agent_state.messages = final_state.get('messages', agent_state.messages)
                
                # Handle command confirmations
                while agent_state.command_to_confirm:
                    command = agent_state.command_to_confirm
                    console.print(Panel(
                        f"¿Ejecutar comando?\n[cyan]{command}[/cyan]",
                        title="⚠️ Confirmación",
                        border_style="yellow",
                        expand=False
                    ))
                    
                    # Simple yes/no input
                    approved = console.input("[bold]¿Aprobar? (s/n):[/bold] ").strip().lower() in ['s', 'si', 'y', 'yes']
                    
                    # Execute handler
                    command_approval_handler.handle_command_approval(
                        command_to_execute=command,
                        auto_approve=approved
                    )
                    
                    agent_state.command_to_confirm = None
                    agent_state.tool_call_id_to_confirm = None
                    
                    if not approved:
                        cli_ui.print_warning("Comando cancelado por el usuario.")
                    
                    # Continue to let agent process result
                    final_state = agent_interaction_manager.invoke_agent(None)
                    agent_state.messages = final_state.get('messages', agent_state.messages)
                
                # Handle tool confirmations
                while agent_state.tool_pending_confirmation:
                    tool_name = agent_state.tool_pending_confirmation
                    diff_info = agent_state.file_update_diff_pending_confirmation
                    
                    message = diff_info.get("action_description", "Confirmación de herramienta requerida.") if isinstance(diff_info, dict) else "Confirmación de herramienta requerida."
                    diff_content = diff_info.get("diff") if isinstance(diff_info, dict) else str(diff_info)
                    file_path = diff_info.get("path") if isinstance(diff_info, dict) else "unknown"
                    
                    if diff_content:
                        cli_ui.print_message(f"[yellow]{message}[/yellow]", style="yellow")
                        console.print(Panel(
                            f"[dim]{diff_content}[/dim]",
                            title=f"📝 {tool_name}: {file_path}",
                            border_style="yellow",
                            expand=False
                        ))
                    
                    approved = console.input("[bold]¿Aprobar? (s/n):[/bold] ").strip().lower() in ['s', 'si', 'y', 'yes']
                    
                    command_approval_handler.handle_command_approval(
                        command_to_execute="",
                        raw_tool_output=diff_info if isinstance(diff_info, dict) else {"status": "requires_confirmation"},
                        auto_approve=approved,
                        tool_name=tool_name,
                        original_tool_args=agent_state.tool_args_pending_confirmation
                    )
                    
                    agent_state.reset_tool_confirmation()
                    
                    if not approved:
                        cli_ui.print_warning("Acción cancelada por el usuario.")
                    
                    # Continue to let agent process result
                    final_state = agent_interaction_manager.invoke_agent(None)
                    agent_state.messages = final_state.get('messages', agent_state.messages)
                
                # Print final response
                messages = final_state.get('messages', [])
                if messages:
                    last_message = messages[-1]
                    if hasattr(last_message, 'content') and last_message.content:
                        cli_ui.print_ai_response(last_message.content)
                
            except Exception as e:
                cli_ui.print_error(f"Error al procesar solicitud: {str(e)}")
                import traceback
                console.print(f"[dim]{traceback.format_exc()}[/dim]")
            
        except KeyboardInterrupt:
            console.print("\n[yellow]Usa %salir para salir[/yellow]")
        except Exception as e:
            console.print(f"[red]Error: {e}[/red]")
            import traceback
            console.print(f"[dim]{traceback.format_exc()}[/dim]")

def main():
    """Main entry point for KogniTerm."""
    # Parse CLI arguments
    parser = argparse.ArgumentParser(prog='kogniterm', description='KogniTerm: Tu asistente de terminal inteligente')
    parser.add_argument('--cli', action='store_true', help='Iniciar en modo CLI simple (Rich, sin TUI)')
    parser.add_argument('--version', action='store_true', help='Mostrar versión')
    args, unknown = parser.parse_known_args()
    
    if args.version:
        console = __import__('rich').Console()
        console.print("[bold cyan]KogniTerm v0.3.5[/bold cyan]")
        return
    
    if args.cli:
        run_simple_cli()
        return
    
    # Desactivar telemetría de CrewAI
    os.environ["CREWAI_TELEMETRY_OPT_OUT"] = "true"
    
    # Silenciar logs de terceros
    logging.getLogger('litellm').setLevel(logging.CRITICAL)
    logging.getLogger('crewai').setLevel(logging.CRITICAL)
    logging.getLogger('CrewAIEventsBus').setLevel(logging.CRITICAL)

    # Si es un comando CLI, ejecutarlo y salir
    if run_cli():
        return

    # Iniciar la aplicación TUI
    try:
        asyncio.run(_main_async())
    except (RuntimeError, KeyboardInterrupt):
        pass
    finally:
        try:
            sys.stdout.flush()
            sys.stderr.flush()
        except:
            pass
        os._exit(0)

if __name__ == "__main__":
    main()