from flask import render_template, request, jsonify, session, abort
import base64
import os
import yaml
import logging
from datetime import datetime, timedelta
import traceback

class Routes:
    def __init__(self, app, chatbot):
        self.app = app
        self.chatbot = chatbot
        
        # Crear directorios necesarios
        self.temp_dir = os.path.join(os.path.dirname(__file__), 'temp')
        self.session_dir = os.path.join(os.path.dirname(__file__), 'sessions')
        self.log_dir = os.path.join(os.path.dirname(__file__), 'logs')
        
        # Asegurar que existan los directorios
        for directory in [self.temp_dir, self.session_dir, self.log_dir]:
            os.makedirs(directory, exist_ok=True)
        
        # Configurar el manejo de sesiones
        self.app.config['SESSION_TYPE'] = 'filesystem'
        self.app.config['SESSION_FILE_DIR'] = self.session_dir
        self.app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=2)
        
        # Inicializar logger
        self.setup_logger()
        
        # Configurar rutas
        self.setup_routes()

    def setup_logger(self):
        """Configurar el logger para la aplicación"""
        log_file = os.path.join(self.log_dir, 'routes.log')
        self.logger = logging.getLogger('routes')
        self.logger.setLevel(logging.DEBUG)
        
        handler = logging.FileHandler(log_file)
        handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
        self.logger.addHandler(handler)
        
        self.logger.info("Rutas inicializadas")

    def setup_routes(self):
        @self.app.route('/')
        def index():
            try:
                # Asegurar que existe la sesión
                session_id = self.chatbot.session_manager.get_session()
                self.logger.info(f"Nueva sesión iniciada: {session_id}")
                
                # Crear directorio de sesión si no existe
                session_path = os.path.join(self.session_dir, session_id)
                os.makedirs(session_path, exist_ok=True)
                
                return render_template('index.html', config=self.app.config)
            except Exception as e:
                self.logger.error(f"Error en index: {str(e)}")
                return render_template('error.html', error="Error al cargar la página")

        @self.app.route('/inferencia', methods=['POST'])
        def inferencia():
            try:
                if not request.is_json:
                    abort(400, "Se requiere contenido JSON")
                    
                data = request.get_json()
                session_id = self.chatbot.session_manager.get_session()
                mensaje = data.get('mensaje')
                
                if not mensaje:
                    return jsonify({
                        'success': False,
                        'error': 'Mensaje vacío'
                    }), 400

                # Obtener respuesta del modelo
                respuesta = self.chatbot.procesar_mensaje(mensaje)
                if not respuesta:
                    return jsonify({
                        'success': False,
                        'error': 'Error al procesar el mensaje'
                    }), 500

                # Guardar mensajes en el historial
                self.chatbot.session_manager.add_message_to_history(session_id, mensaje, 'user')
                self.chatbot.session_manager.add_message_to_history(session_id, respuesta, 'bot')

                return jsonify({
                    'success': True,
                    'texto': respuesta,
                    'session_id': session_id
                })

            except Exception as e:
                self.logger.error(f"Error en inferencia: {str(e)}\n{traceback.format_exc()}")
                return jsonify({
                    'success': False,
                    'error': 'Error interno del servidor'
                }), 500

        @self.app.route('/generar_audio', methods=['POST'])
        def generar_audio():
            try:
                session_id = self.chatbot.session_manager.get_session()
                data = request.get_json()
                texto = data.get('texto', '')
                tts_model = data.get('tts', 'EDGE')

                if not texto:
                    return jsonify({
                        'success': False,
                        'error': 'No se recibió texto para generar audio'
                    })

                # Crear directorio temporal si no existe
                temp_dir = os.path.join(os.path.dirname(__file__), 'temp')
                os.makedirs(temp_dir, exist_ok=True)
                
                # Generar nombre único para el archivo temporal
                temp_file = os.path.join(temp_dir, f"temp_audio_{os.urandom(4).hex()}.mp3")
                
                # Generar el audio
                print(f"Generando audio para: {texto[:50]}...")
                audio_path = self.chatbot.tts.text_to_speech(texto, save_path=temp_file)
                
                if not audio_path or not os.path.exists(audio_path):
                    raise Exception('No se pudo generar el archivo de audio')
                
                # Verificar tamaño del archivo
                if os.path.getsize(audio_path) == 0:
                    raise Exception('El archivo de audio generado está vacío')
                
                # Convertir audio a base64
                try:
                    with open(audio_path, 'rb') as audio_file:
                        audio_data = base64.b64encode(audio_file.read()).decode('utf-8')
                finally:
                    # Limpiar archivo temporal
                    try:
                        os.remove(audio_path)
                    except Exception as e:
                        print(f"Error eliminando archivo temporal: {e}")
                
                # Actualizar estado del audio en la sesión
                self.chatbot.session_manager.update_audio_state(
                    session_id,
                    is_playing=True,
                    current_audio=audio_data
                )

                print("Audio generado correctamente")
                return jsonify({
                    'success': True,
                    'audio': audio_data,
                    'audio_type': 'mp3'
                })

            except Exception as e:
                print(f"Error generando audio: {str(e)}")
                return jsonify({
                    'success': False,
                    'error': str(e)
                })

        @self.app.route('/chat', methods=['POST'])
        def chat():
            try:
                session_id = self.chatbot.session_manager.get_session()
                data = request.get_json()
                
                # Obtener todos los parámetros necesarios
                mensaje = data.get('mensaje', '')
                mode = data.get('mode', 'soporte')
                model = data.get('model', 'gemini')
                tts = data.get('tts', 'EDGE')
                
                self.logger.info(f"Chat - Sesión: {session_id} | Mensaje: {mensaje} | Modo: {mode}")
                
                if not mensaje:
                    return jsonify({
                        'success': False,
                        'error': 'No se recibió mensaje para procesar'
                    })
                
                # Crear directorio de sesión si no existe
                session_path = os.path.join(self.session_dir, session_id)
                os.makedirs(session_path, exist_ok=True)
                
                # Guardar mensaje en archivo de historial
                history_file = os.path.join(session_path, 'chat_history.txt')
                with open(history_file, 'a', encoding='utf-8') as f:
                    f.write(f"Usuario ({datetime.now()}): {mensaje}\n")
                
                # Actualizar modo y modelo en la sesión
                self.chatbot.session_manager.update_session(session_id, 'mode', mode)
                self.chatbot.session_manager.update_session(session_id, 'model', model)
                self.chatbot.session_manager.update_session(session_id, 'tts', tts)
                
                # Obtener respuesta del modelo
                respuesta = self.chatbot.procesar_mensaje(mensaje)
                if not respuesta:
                    return jsonify({
                        'success': False,
                        'error': 'No se pudo obtener respuesta del modelo'
                    })
                
                print(f"Respuesta generada: {respuesta}")
                
                # Guardar mensajes en el historial
                self.chatbot.session_manager.add_message_to_history(session_id, mensaje, 'user')
                self.chatbot.session_manager.add_message_to_history(session_id, respuesta, 'bot')
                
                # Generar el audio
                try:
                    temp_dir = os.path.join(os.path.dirname(__file__), 'temp')
                    os.makedirs(temp_dir, exist_ok=True)
                    temp_file = os.path.join(temp_dir, f"temp_audio_{os.urandom(4).hex()}.wav")
                    
                    print("Generando audio para la respuesta...")
                    audio_path = self.chatbot.tts.text_to_speech(respuesta, save_path=temp_file)
                    
                    if not audio_path or not os.path.exists(audio_path):
                        print("No se pudo generar el archivo de audio")
                        return jsonify({
                            'success': True,
                            'texto': respuesta,
                            'session_id': session_id
                        })
                    
                    with open(audio_path, 'rb') as audio_file:
                        audio_data = base64.b64encode(audio_file.read()).decode('utf-8')
                    
                    try:
                        os.remove(audio_path)
                    except:
                        pass
                    
                    self.chatbot.session_manager.update_audio_state(
                        session_id,
                        is_playing=True,
                        current_audio=audio_data
                    )
                    
                    print("Audio generado correctamente")
                    return jsonify({
                        'success': True,
                        'texto': respuesta,
                        'audio': audio_data,
                        'audio_type': 'wav',
                        'session_id': session_id
                    })
                    
                except Exception as audio_error:
                    print(f"Error generando audio: {audio_error}")
                    return jsonify({
                        'success': True,
                        'texto': respuesta,
                        'session_id': session_id
                    })
                
            except Exception as e:
                print(f"Error en chat: {str(e)}")
                return jsonify({
                    'success': False,
                    'error': str(e)
                })

        @self.app.route('/procesar_voz', methods=['POST'])
        def procesar_voz():
            try:
                session_id = self.chatbot.session_manager.get_session()
                data = request.get_json()
                
                # Obtener todos los parámetros necesarios
                texto = data.get('texto', '')
                mode = data.get('mode', 'soporte')
                model = data.get('model', 'gemini')
                tts = data.get('tts', 'EDGE')
                
                self.logger.info(f"Voz - Sesión: {session_id} | Texto: {texto} | Modo: {mode}")
                
                if not texto:
                    return jsonify({
                        'success': False,
                        'error': 'No se recibió texto para procesar'
                    })
                
                # Crear directorio de sesión si no existe
                session_path = os.path.join(self.session_dir, session_id)
                os.makedirs(session_path, exist_ok=True)
                
                # Guardar mensaje en archivo de historial
                history_file = os.path.join(session_path, 'chat_history.txt')
                with open(history_file, 'a', encoding='utf-8') as f:
                    f.write(f"Voz ({datetime.now()}): {texto}\n")
                
                # Actualizar modo y modelo en la sesión
                self.chatbot.session_manager.update_session(session_id, 'mode', mode)
                self.chatbot.session_manager.update_session(session_id, 'model', model)
                self.chatbot.session_manager.update_session(session_id, 'tts', tts)
                
                # Obtener respuesta del modelo
                respuesta = self.chatbot.procesar_mensaje(texto)
                if not respuesta:
                    self.logger.error(f"No se pudo obtener respuesta para: {texto}")
                    return jsonify({
                        'success': False,
                        'error': 'No se pudo obtener respuesta del modelo'
                    })
                
                self.logger.info(f"Respuesta generada: {respuesta}")
                
                # Guardar respuesta en historial
                with open(history_file, 'a', encoding='utf-8') as f:
                    f.write(f"Bot ({datetime.now()}): {respuesta}\n")
                
                # Guardar mensajes en el historial de sesión
                self.chatbot.session_manager.add_message_to_history(session_id, texto, 'user')
                self.chatbot.session_manager.add_message_to_history(session_id, respuesta, 'bot')
                
                # Generar el audio
                try:
                    temp_file = os.path.join(self.temp_dir, f"temp_audio_{os.urandom(4).hex()}.wav")
                    
                    self.logger.info("Generando audio para la respuesta de voz...")
                    audio_path = self.chatbot.tts.text_to_speech(respuesta, save_path=temp_file)
                    
                    if not audio_path or not os.path.exists(audio_path):
                        self.logger.error("No se pudo generar el archivo de audio")
                        return jsonify({
                            'success': True,
                            'texto': respuesta,
                            'session_id': session_id
                        })
                    
                    with open(audio_path, 'rb') as audio_file:
                        audio_data = base64.b64encode(audio_file.read()).decode('utf-8')
                    
                    try:
                        os.remove(audio_path)
                    except Exception as e:
                        self.logger.warning(f"Error limpiando archivo temporal: {e}")
                    
                    self.chatbot.session_manager.update_audio_state(
                        session_id,
                        is_playing=True,
                        current_audio=audio_data
                    )
                    
                    self.logger.info("Audio generado correctamente")
                    return jsonify({
                        'success': True,
                        'texto': respuesta,
                        'audio': audio_data,
                        'audio_type': 'wav',
                        'session_id': session_id
                    })
                    
                except Exception as audio_error:
                    self.logger.error(f"Error generando audio: {audio_error}")
                    return jsonify({
                        'success': True,
                        'texto': respuesta,
                        'session_id': session_id
                    })
                
            except Exception as e:
                self.logger.error(f"Error en procesar_voz: {str(e)}")
                return jsonify({
                    'success': False,
                    'error': str(e)
                })

        @self.app.route('/cambiar_modo', methods=['POST'])
        def cambiar_modo():
            try:
                session_id = self.chatbot.session_manager.get_session()
                data = request.get_json()
                mode = data.get('mode')
                
                if not mode:
                    return jsonify({
                        'success': False,
                        'error': 'No se especificó el modo'
                    })
                
                self.logger.info(f"Cambiando modo - Sesión: {session_id} | Modo: {mode}")
                
                if mode in self.chatbot.flow_bot.FLOWS:
                    self.chatbot.session_manager.update_session(session_id, 'mode', mode)
                    mensaje = self.chatbot.flow_bot.get_success_message(mode)
                    
                    # Guardar cambio de modo en historial
                    session_path = os.path.join(self.session_dir, session_id)
                    os.makedirs(session_path, exist_ok=True)
                    history_file = os.path.join(session_path, 'chat_history.txt')
                    with open(history_file, 'a', encoding='utf-8') as f:
                        f.write(f"Sistema ({datetime.now()}): Cambio a modo {mode}\n")
                        f.write(f"Bot ({datetime.now()}): {mensaje}\n")
                    
                    # Generar audio para el mensaje
                    try:
                        temp_file = os.path.join(self.temp_dir, f"temp_audio_{os.urandom(4).hex()}.wav")
                        
                        self.logger.info("Generando audio para cambio de modo...")
                        audio_path = self.chatbot.tts.text_to_speech(mensaje, save_path=temp_file)
                        
                        if not audio_path or not os.path.exists(audio_path):
                            self.logger.error("No se pudo generar el archivo de audio para el modo")
                            return jsonify({
                                'success': True,
                                'texto': mensaje
                            })
                        
                        with open(audio_path, 'rb') as audio_file:
                            audio_data = base64.b64encode(audio_file.read()).decode('utf-8')
                        
                        try:
                            os.remove(audio_path)
                        except Exception as e:
                            self.logger.warning(f"Error limpiando archivo temporal: {e}")
                        
                        self.logger.info("Audio de modo generado correctamente")
                        return jsonify({
                            'success': True,
                            'texto': mensaje,
                            'audio': audio_data,
                            'audio_type': 'wav'
                        })
                        
                    except Exception as audio_error:
                        self.logger.error(f"Error generando audio de modo: {audio_error}")
                        return jsonify({
                            'success': True,
                            'texto': mensaje
                        })
                
                return jsonify({
                    'success': False,
                    'error': 'Modo no válido'
                })
                
            except Exception as e:
                self.logger.error(f"Error cambiando modo: {str(e)}")
                return jsonify({
                    'success': False,
                    'error': str(e)
                })

        @self.app.route('/cambiar_modelo', methods=['POST'])
        def cambiar_modelo():
            try:
                session_id = self.chatbot.session_manager.get_session()
                data = request.get_json()
                model = data.get('model', 'gemini')
                self.chatbot.session_manager.update_session(session_id, 'model', model)
                print(f"Modelo cambiado a: {model}")
                return jsonify({'success': True})
            except Exception as e:
                print(f"Error cambiando modelo: {str(e)}")
                return jsonify({'success': False, 'error': str(e)})

        @self.app.route('/cambiar_tts', methods=['POST'])
        def cambiar_tts():
            try:
                session_id = self.chatbot.session_manager.get_session()
                data = request.get_json()
                tts = data.get('model')
                
                print(f"Solicitud de cambio de modelo TTS recibida: {tts}")
                
                if not tts or tts not in ['EDGE', 'EDGE_ES', 'VITS']:
                    print(f"Modelo TTS inválido: {tts}")
                    return jsonify({
                        'error': 'Modelo de voz inválido'
                    }), 400
                
                # Actualizar el modelo TTS
                self.chatbot.tts.current_model = tts
                self.chatbot.session_manager.update_session(session_id, 'tts', tts)
                
                print(f"TTS cambiado exitosamente a: {tts}")
                return jsonify({'success': True})
            except Exception as e:
                print(f"Error cambiando TTS: {str(e)}")
                return jsonify({'success': False, 'error': str(e)})

        @self.app.route('/get_session_data', methods=['GET'])
        def get_session_data():
            try:
                session_id = self.chatbot.session_manager.get_session()
                data = self.chatbot.session_manager.get_session_data(session_id)
                return jsonify(data)
            except Exception as e:
                print(f"Error obteniendo datos de sesión: {str(e)}")
                return jsonify({'error': str(e)})

        @self.app.route('/update_audio_state', methods=['POST'])
        def update_audio_state():
            session_id = self.chatbot.session_manager.get_session()
            is_playing = request.json.get('is_playing', False)
            current_audio = request.json.get('current_audio')
            self.chatbot.session_manager.update_audio_state(
                session_id,
                is_playing=is_playing,
                current_audio=current_audio
            )
            return jsonify({'success': True})

        @self.app.route('/save_config', methods=['POST'])
        def save_config():
            try:
                config_data = request.json
                
                # Actualizar el archivo config.yaml
                config_path = os.path.join(os.path.dirname(__file__), 'config.yaml')
                with open(config_path, 'r') as file:
                    current_config = yaml.safe_load(file) or {}
                
                # Actualizar solo las claves de API
                current_config['OPENAI_API_KEY'] = config_data.get('openai_key', '')
                current_config['HUGGINGFACE_TOKEN'] = config_data.get('huggingface_key', '')
                current_config['ELEVENLABS_API_KEY'] = config_data.get('elevenlabs_key', '')
                
                with open(config_path, 'w') as file:
                    yaml.dump(current_config, file)
                
                # Reiniciar los componentes que usan las APIs
                self.chatbot.reinit_components()
                
                return jsonify({'status': 'success'})
            except Exception as e:
                return jsonify({'status': 'error', 'message': str(e)}), 500

        @self.app.route('/get_config')
        def get_config():
            try:
                config_path = os.path.join(os.path.dirname(__file__), 'config.yaml')
                with open(config_path, 'r') as file:
                    current_config = yaml.safe_load(file) or {}
                
                return jsonify({
                    'openai_key': current_config.get('OPENAI_API_KEY', ''),
                    'huggingface_key': current_config.get('HUGGINGFACE_TOKEN', ''),
                    'elevenlabs_key': current_config.get('ELEVENLABS_API_KEY', '')
                })
            except Exception as e:
                return jsonify({'status': 'error', 'message': str(e)}), 500

        @self.app.errorhandler(404)
        def not_found_error(error):
            return jsonify({'error': 'Recurso no encontrado'}), 404

        @self.app.errorhandler(500)
        def internal_error(error):
            return jsonify({'error': 'Error interno del servidor'}), 500