"""
Router para manejo de comparaciones guardadas de llantas.
"""
from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required
from app.db import get_db_connection
from app.auth import get_current_user
from app.utils.validators import validate_id_format, validate_length, validate_pagination_params
from app.utils.serializers import saved_comparison_to_dict, tire_to_dict
from app.utils.logger import get_logger
from datetime import datetime, timezone
import uuid
import json
import secrets

comparisons_bp = Blueprint('comparisons', __name__)
logger = get_logger(__name__)


@comparisons_bp.route('', methods=['GET'])
@jwt_required()
def get_saved_comparisons():
    """Get all saved comparisons for the current user."""
    user = get_current_user()
    if not user:
        return jsonify({'error': 'Authentication required'}), 401
    
    skip = request.args.get('skip', 0, type=int)
    limit = request.args.get('limit', 50, type=int)
    
    # Validar paginación
    valid, skip_val, limit_val, error_msg = validate_pagination_params(skip, limit, max_limit=100)
    if not valid:
        return jsonify({'error': error_msg}), 400
    
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection error'}), 500
    
    try:
        cursor = conn.cursor()
        user_id = user.get('id')
        
        cursor.execute("""
            SELECT id, usuario_id, nombre, llantas_ids, notas, compartir_token, creado_en, actualizado_en
            FROM comparaciones_guardadas
            WHERE usuario_id = %s
            ORDER BY actualizado_en DESC
            LIMIT %s OFFSET %s
        """, (user_id, limit_val, skip_val))
        
        comparisons_data = cursor.fetchall()
        
        # Contar total
        cursor.execute("SELECT COUNT(*) as total FROM comparaciones_guardadas WHERE usuario_id = %s", (user_id,))
        total_result = cursor.fetchone()
        total_count = total_result['total'] if total_result else 0
        
        cursor.close()
        conn.close()
        
        return jsonify({
            'comparisons': [saved_comparison_to_dict(comp) for comp in comparisons_data],
            'pagination': {
                'skip': skip_val,
                'limit': limit_val,
                'total': total_count,
                'has_more': (skip_val + limit_val) < total_count
            }
        }), 200
    
    except Exception as e:
        if 'cursor' in locals():
            cursor.close()
        if conn:
            conn.close()
        logger.error(f"Error in get_saved_comparisons: {str(e)}", exc_info=True, extra={
            'endpoint': 'get_saved_comparisons',
            'user_id': user.get('id') if user else None
        })
        return jsonify({'error': 'Error retrieving saved comparisons'}), 500


@comparisons_bp.route('/shared/<share_token>', methods=['GET'])
def get_shared_comparison(share_token):
    """Get a shared comparison by share token. Public endpoint."""
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection error'}), 500
    
    try:
        cursor = conn.cursor()
        
        cursor.execute("""
            SELECT id, usuario_id, nombre, llantas_ids, notas, compartir_token, creado_en, actualizado_en
            FROM comparaciones_guardadas
            WHERE compartir_token = %s
        """, (share_token,))
        
        comparison_data = cursor.fetchone()
        
        if not comparison_data:
            cursor.close()
            conn.close()
            return jsonify({'error': 'Shared comparison not found'}), 404
        
        # Obtener información de las llantas
        comparison_dict = saved_comparison_to_dict(comparison_data)
        tire_ids = comparison_dict.get('tire_ids', [])
        
        if tire_ids:
            placeholders = ','.join(['%s'] * len(tire_ids))
            cursor.execute(f"""
                SELECT id, marca, modelo, ancho, relacion_aspecto, diametro, tipo, url_imagen, creado_en
                FROM llantas
                WHERE id IN ({placeholders})
            """, tire_ids)
            
            tires_data = cursor.fetchall()
            comparison_dict['tires'] = [tire_to_dict(tire) for tire in tires_data]
        else:
            comparison_dict['tires'] = []
        
        cursor.close()
        conn.close()
        
        return jsonify(comparison_dict), 200
    
    except Exception as e:
        if 'cursor' in locals():
            cursor.close()
        if conn:
            conn.close()
        logger.error(f"Error in get_shared_comparison: {str(e)}", exc_info=True, extra={
            'endpoint': 'get_shared_comparison',
            'share_token': share_token
        })
        return jsonify({'error': 'Error retrieving shared comparison'}), 500


@comparisons_bp.route('', methods=['POST'])
@jwt_required()
def create_saved_comparison():
    """Create a new saved comparison."""
    user = get_current_user()
    if not user:
        return jsonify({'error': 'Authentication required'}), 401
    
    data = request.get_json()
    if not data:
        return jsonify({'error': 'Request body is required'}), 400
    
    name = data.get('name', '').strip()
    tire_ids = data.get('tire_ids', [])
    notes = data.get('notes', '').strip()
    
    if not tire_ids or not isinstance(tire_ids, list):
        return jsonify({'error': 'tire_ids is required and must be an array'}), 400
    
    if len(tire_ids) < 2:
        return jsonify({'error': 'At least 2 tires are required for comparison'}), 400
    
    if len(tire_ids) > 10:
        return jsonify({'error': 'Maximum 10 tires allowed for comparison'}), 400
    
    # Validar formato de IDs y longitud de nombre/notas
    for tire_id in tire_ids:
        if not validate_id_format(tire_id):
            return jsonify({'error': f'Invalid tire_id format: {tire_id}'}), 400
    
    if name and not validate_length(name, max_length=255):
        return jsonify({'error': 'Name must not exceed 255 characters'}), 400
    
    if notes and not validate_length(notes, max_length=2000):
        return jsonify({'error': 'Notes must not exceed 2000 characters'}), 400
    
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection error'}), 500
    
    try:
        cursor = conn.cursor()
        user_id = user.get('id')
        
        # Verificar que todas las llantas existen
        placeholders = ','.join(['%s'] * len(tire_ids))
        cursor.execute(f"""
            SELECT id FROM llantas WHERE id IN ({placeholders})
        """, tire_ids)
        
        existing_tires = {row['id'] for row in cursor.fetchall()}
        missing_tires = set(tire_ids) - existing_tires
        
        if missing_tires:
            cursor.close()
            conn.close()
            return jsonify({'error': f'Tires not found: {", ".join(missing_tires)}'}), 404
        
        # Crear comparación
        comparison_id = f"comp-{user_id}-{uuid.uuid4().hex[:12]}"
        share_token = secrets.token_urlsafe(32)
        tire_ids_json = json.dumps(tire_ids)
        
        cursor.execute("""
            INSERT INTO comparaciones_guardadas (id, usuario_id, nombre, llantas_ids, notas, compartir_token, creado_en)
            VALUES (%s, %s, %s, %s, %s, %s, %s)
        """, (comparison_id, user_id, name or None, tire_ids_json, notes or None, share_token, datetime.now(timezone.utc)))
        
        conn.commit()
        
        # Log change for audit
        from app.governance.audit import log_change
        log_change(
            table='comparaciones_guardadas',
            record_id=comparison_id,
            action='INSERT',
            user_id=user_id,
            user_email=user.get('correo'),
            new_data={
                'usuario_id': user_id,
                'nombre': name,
                'llantas_ids': tire_ids,
                'compartir_token': share_token
            }
        )
        
        # Obtener comparación creada
        cursor.execute("""
            SELECT id, usuario_id, nombre, llantas_ids, notas, compartir_token, creado_en, actualizado_en
            FROM comparaciones_guardadas WHERE id = %s
        """, (comparison_id,))
        comparison_data = cursor.fetchone()
        
        cursor.close()
        conn.close()
        
        return jsonify(saved_comparison_to_dict(comparison_data)), 201
    
    except Exception as e:
        if conn:
            conn.rollback()
            if 'cursor' in locals():
                cursor.close()
            conn.close()
        logger.error(f"Error in create_saved_comparison: {str(e)}", exc_info=True, extra={
            'endpoint': 'create_saved_comparison',
            'user_id': user.get('id') if user else None
        })
        return jsonify({'error': 'Error creating saved comparison'}), 500


@comparisons_bp.route('/<comparison_id>', methods=['GET'])
@jwt_required()
def get_saved_comparison(comparison_id):
    """Get a specific saved comparison with tire details."""
    user = get_current_user()
    if not user:
        return jsonify({'error': 'Authentication required'}), 401
    
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection error'}), 500
    
    try:
        cursor = conn.cursor()
        user_id = user.get('id')
        
        cursor.execute("""
            SELECT id, usuario_id, nombre, llantas_ids, notas, compartir_token, creado_en, actualizado_en
            FROM comparaciones_guardadas
            WHERE id = %s AND usuario_id = %s
        """, (comparison_id, user_id))
        
        comparison_data = cursor.fetchone()
        
        if not comparison_data:
            cursor.close()
            conn.close()
            return jsonify({'error': 'Comparison not found'}), 404
        
        # Obtener información de las llantas
        comparison_dict = saved_comparison_to_dict(comparison_data)
        tire_ids = comparison_dict.get('tire_ids', [])
        
        if tire_ids:
            placeholders = ','.join(['%s'] * len(tire_ids))
            cursor.execute(f"""
                SELECT id, marca, modelo, ancho, relacion_aspecto, diametro, tipo, url_imagen, creado_en
                FROM llantas
                WHERE id IN ({placeholders})
            """, tire_ids)
            
            tires_data = cursor.fetchall()
            comparison_dict['tires'] = [tire_to_dict(tire) for tire in tires_data]
            
            # Enriquecer con información de precios del inventario
            for tire in comparison_dict['tires']:
                cursor.execute("""
                    SELECT MIN(precio) as min_price, MAX(precio) as max_price, SUM(cantidad) as total_stock
                    FROM items_inventario
                    WHERE llanta_id = %s AND cantidad > 0
                """, (tire['id'],))
                
                price_data = cursor.fetchone()
                if price_data and price_data.get('min_price'):
                    tire['minPrice'] = float(price_data['min_price'])
                    tire['maxPrice'] = float(price_data['max_price'])
                    tire['totalStock'] = int(price_data['total_stock'] or 0)
                else:
                    tire['minPrice'] = None
                    tire['maxPrice'] = None
                    tire['totalStock'] = 0
        else:
            comparison_dict['tires'] = []
        
        cursor.close()
        conn.close()
        
        return jsonify(comparison_dict), 200
    
    except Exception as e:
        if 'cursor' in locals():
            cursor.close()
        if conn:
            conn.close()
        logger.error(f"Error in get_saved_comparison: {str(e)}", exc_info=True, extra={
            'endpoint': 'get_saved_comparison',
            'user_id': user.get('id') if user else None,
            'comparison_id': comparison_id
        })
        return jsonify({'error': 'Error retrieving saved comparison'}), 500


@comparisons_bp.route('/<comparison_id>', methods=['PUT'])
@jwt_required()
def update_saved_comparison(comparison_id):
    """Update a saved comparison."""
    user = get_current_user()
    if not user:
        return jsonify({'error': 'Authentication required'}), 401
    
    data = request.get_json()
    if not data:
        return jsonify({'error': 'Request body is required'}), 400
    
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection error'}), 500
    
    try:
        cursor = conn.cursor()
        user_id = user.get('id')
        
        # Verificar que la comparación existe y pertenece al usuario
        cursor.execute("""
            SELECT id, nombre, llantas_ids, notas FROM comparaciones_guardadas
            WHERE id = %s AND usuario_id = %s
        """, (comparison_id, user_id))
        
        comparison_data = cursor.fetchone()
        if not comparison_data:
            cursor.close()
            conn.close()
            return jsonify({'error': 'Comparison not found'}), 404
        
        updates = []
        params = []
        
        # Actualizar nombre
        if 'name' in data:
            name = data['name'].strip() if data['name'] else None
            if name and not validate_length(name, max_length=255):
                cursor.close()
                conn.close()
                return jsonify({'error': 'Name must not exceed 255 characters'}), 400
            updates.append("nombre = %s")
            params.append(name)
        
        # Actualizar notas
        if 'notes' in data:
            notes = data['notes'].strip() if data['notes'] else None
            if notes and not validate_length(notes, max_length=2000):
                cursor.close()
                conn.close()
                return jsonify({'error': 'Notes must not exceed 2000 characters'}), 400
            updates.append("notas = %s")
            params.append(notes)
        
        # Actualizar tire_ids
        if 'tire_ids' in data:
            tire_ids = data['tire_ids']
            if not isinstance(tire_ids, list):
                cursor.close()
                conn.close()
                return jsonify({'error': 'tire_ids must be an array'}), 400
            
            if len(tire_ids) < 2:
                cursor.close()
                conn.close()
                return jsonify({'error': 'At least 2 tires are required for comparison'}), 400
            
            if len(tire_ids) > 10:
                cursor.close()
                conn.close()
                return jsonify({'error': 'Maximum 10 tires allowed for comparison'}), 400
            
            # Validar formato de IDs
            for tire_id in tire_ids:
                if not validate_id_format(tire_id):
                    cursor.close()
                    conn.close()
                    return jsonify({'error': f'Invalid tire_id format: {tire_id}'}), 400
            
            # Verificar que todas las llantas existen
            placeholders = ','.join(['%s'] * len(tire_ids))
            cursor.execute(f"""
                SELECT id FROM llantas WHERE id IN ({placeholders})
            """, tire_ids)
            
            existing_tires = {row['id'] for row in cursor.fetchall()}
            missing_tires = set(tire_ids) - existing_tires
            
            if missing_tires:
                cursor.close()
                conn.close()
                return jsonify({'error': f'Tires not found: {", ".join(missing_tires)}'}), 404
            
            tire_ids_json = json.dumps(tire_ids)
            updates.append("llantas_ids = %s")
            params.append(tire_ids_json)
        
        if updates:
            params.append(datetime.now(timezone.utc))
            params.append(comparison_id)
            cursor.execute(f"""
                UPDATE comparaciones_guardadas
                SET {', '.join(updates)}, actualizado_en = %s
                WHERE id = %s
            """, params)
            conn.commit()
        
        # Obtener comparación actualizada
        cursor.execute("""
            SELECT id, usuario_id, nombre, llantas_ids, notas, compartir_token, creado_en, actualizado_en
            FROM comparaciones_guardadas WHERE id = %s
        """, (comparison_id,))
        updated_comparison = cursor.fetchone()
        
        cursor.close()
        conn.close()
        
        return jsonify(saved_comparison_to_dict(updated_comparison)), 200
    
    except Exception as e:
        if conn:
            conn.rollback()
            if 'cursor' in locals():
                cursor.close()
            conn.close()
        logger.error(f"Error in update_saved_comparison: {str(e)}", exc_info=True, extra={
            'endpoint': 'update_saved_comparison',
            'user_id': user.get('id') if user else None,
            'comparison_id': comparison_id
        })
        return jsonify({'error': 'Error updating saved comparison'}), 500


@comparisons_bp.route('/<comparison_id>', methods=['DELETE'])
@jwt_required()
def delete_saved_comparison(comparison_id):
    """Delete a saved comparison."""
    user = get_current_user()
    if not user:
        return jsonify({'error': 'Authentication required'}), 401
    
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection error'}), 500
    
    try:
        cursor = conn.cursor()
        user_id = user.get('id')
        
        # Verificar que la comparación existe y pertenece al usuario
        cursor.execute("""
            SELECT id FROM comparaciones_guardadas
            WHERE id = %s AND usuario_id = %s
        """, (comparison_id, user_id))
        
        if not cursor.fetchone():
            cursor.close()
            conn.close()
            return jsonify({'error': 'Comparison not found'}), 404
        
        # Eliminar comparación
        cursor.execute("DELETE FROM comparaciones_guardadas WHERE id = %s", (comparison_id,))
        conn.commit()
        
        # Log change for audit
        from app.governance.audit import log_change
        log_change(
            table='comparaciones_guardadas',
            record_id=comparison_id,
            action='DELETE',
            user_id=user_id,
            user_email=user.get('correo')
        )
        
        cursor.close()
        conn.close()
        
        return '', 204
    
    except Exception as e:
        if conn:
            conn.rollback()
            if 'cursor' in locals():
                cursor.close()
            conn.close()
        logger.error(f"Error in delete_saved_comparison: {str(e)}", exc_info=True, extra={
            'endpoint': 'delete_saved_comparison',
            'user_id': user.get('id') if user else None,
            'comparison_id': comparison_id
        })
        return jsonify({'error': 'Error deleting saved comparison'}), 500


@comparisons_bp.route('/<comparison_id>/share-token', methods=['POST'])
@jwt_required()
def regenerate_share_token(comparison_id):
    """Regenerate share token for a comparison."""
    user = get_current_user()
    if not user:
        return jsonify({'error': 'Authentication required'}), 401
    
    conn = get_db_connection()
    if not conn:
        return jsonify({'error': 'Database connection error'}), 500
    
    try:
        cursor = conn.cursor()
        user_id = user.get('id')
        
        # Verificar que la comparación existe y pertenece al usuario
        cursor.execute("""
            SELECT id FROM comparaciones_guardadas
            WHERE id = %s AND usuario_id = %s
        """, (comparison_id, user_id))
        
        if not cursor.fetchone():
            cursor.close()
            conn.close()
            return jsonify({'error': 'Comparison not found'}), 404
        
        # Generar nuevo token
        new_token = secrets.token_urlsafe(32)
        
        cursor.execute("""
            UPDATE comparaciones_guardadas
            SET compartir_token = %s, actualizado_en = %s
            WHERE id = %s
        """, (new_token, datetime.now(timezone.utc), comparison_id))
        
        conn.commit()
        
        # Obtener comparación actualizada
        cursor.execute("""
            SELECT id, usuario_id, nombre, llantas_ids, notas, compartir_token, creado_en, actualizado_en
            FROM comparaciones_guardadas WHERE id = %s
        """, (comparison_id,))
        updated_comparison = cursor.fetchone()
        
        cursor.close()
        conn.close()
        
        return jsonify(saved_comparison_to_dict(updated_comparison)), 200
    
    except Exception as e:
        if conn:
            conn.rollback()
            if 'cursor' in locals():
                cursor.close()
            conn.close()
        logger.error(f"Error in regenerate_share_token: {str(e)}", exc_info=True, extra={
            'endpoint': 'regenerate_share_token',
            'user_id': user.get('id') if user else None,
            'comparison_id': comparison_id
        })
        return jsonify({'error': 'Error regenerating share token'}), 500
