from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.core.exceptions import ValidationError
from django.forms.models import model_to_dict
import json

# --- Modelos ---
from usuarios.models import Url
from login.models import Area

# --- 🌟 IMPORTACIONES AÑADIDAS (para Pillow y guardado de archivos) ---
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage
from django.conf import settings
import os # <-- 🌟 IMPORTADO PARA MANEJAR NOMBRES DE ARCHIVO


# ---------------------- #
# VISTA PRINCIPAL #
# ---------------------- #
@csrf_exempt
def gestion_bi_view(request):
  if 'user_id' not in request.session or request.session.get('user_tipo') == 2 or request.session.get('user_tipo') == 3:
    # Redirigir al login si no hay sesión
    return redirect('/')
  """Vista principal del módulo BI"""
  return render(request, 'gestion_bi.html')

# ---------------------- #
# ENDPOINTS GET #
# ---------------------- #
@csrf_exempt
@require_http_methods(["GET"]) 
def get_urls(request):
  """
  Retorna todas las URLs con su área asociada.
  Reconstruye la URL de la imagen para el frontend.
  """
  urls = Url.objects.select_related('area').all().order_by('-fecha_creacion') 

  data = [
    {
      "id": u.id,
      "nombre": u.nombre,
      "url": u.url,
      "area_id": getattr(u.area, 'id', None),
      "area_nombre": getattr(u.area, 'nombre', None),
      "descrip": u.descrip,
      
      # Reconstruir la URL completa para el frontend
      "img_descrip_url": f"{settings.MEDIA_URL}informes/{u.img_descrip}" if u.img_descrip else None,
      
      "tipo": u.tipo,
      "fecha_creacion": u.fecha_creacion.strftime('%Y-%m-%d %H:%M:%S')
    }
    for u in urls
  ]
  return JsonResponse({"result": data, "count": len(data)})

@csrf_exempt
@require_http_methods(["GET"])
def areas_list(request):
  """Lista de áreas disponibles para asociar a URLs."""
  areas = Area.objects.filter(urls__isnull=False).distinct().values("id", "nombre").order_by("nombre")
  return JsonResponse({"result": list(areas), "count": areas.count()})

# ---------------------- #
# ENDPOINT POST (ADD) #
# ---------------------- #

@csrf_exempt
@require_http_methods(["POST"])
def add_url(request):
  """
  Crea una nueva URL y maneja la subida de una imagen.
  """
  try:
    data = request.POST
    files = request.FILES

    nombre = data.get('nombre')
    url_str = data.get('url')
    area_id = data.get('area_id')
    descrip = data.get('descrip')
    tipo = data.get('tipo') 
    
    if not all([nombre, url_str, area_id]):
      return JsonResponse({'status': 'error', 'message': 'Faltan campos obligatorios (nombre, url, area_id)'}, status=400)

    try:
      area = Area.objects.get(id=area_id)
    except Area.DoesNotExist:
      return JsonResponse({'status': 'error', 'message': 'Área no encontrada'}, status=404)

    # PASO 1: Crear el objeto URL PRIMERO (con imagen vacía)
    url_obj = Url.objects.create(
      nombre=nombre,
      url=url_str,
      area=area,
      descrip=descrip or '',
      img_descrip='', # Se guarda vacío temporalmente
      tipo=tipo or 'Informe',
    )

    # PASO 2: Procesar la imagen AHORA, usando el ID del objeto
    img_db_name = ''
    
    if 'img_descrip' in files:
      image_file = files['img_descrip']
      
      try:
        img = Image.open(image_file)
        img.verify()
        img = Image.open(image_file)
        
        if img.mode in ('RGBA', 'P'):
          img = img.convert('RGB')
        
        img.thumbnail((1000, 1000))
        
        thumb_io = BytesIO()
        # Se fuerza el formato JPEG
        img.save(thumb_io, format='JPEG', quality=85) 
        
        thumb_file = ContentFile(thumb_io.getvalue())
        
        fs = FileSystemStorage()
        
        # PASO 3: Crear el nuevo nombre de archivo usando el ID
        filename_base = f"Informe-{url_obj.id}"
        save_path = f"informes/{filename_base}.jpg"
        
        # Borrar si ya existiera con ese nombre 
        if fs.exists(save_path):
          fs.delete(save_path)
          
        filename = fs.save(save_path, thumb_file)
        
        # Guardar solo el nombre del archivo (ej: "Informe-123.jpg")
        img_db_name = os.path.basename(filename)

        # PASO 4: Actualizar el objeto Url con el nombre de la imagen
        url_obj.img_descrip = img_db_name
        url_obj.save(update_fields=['img_descrip'])

      except Exception as e:
        # Si la imagen falla, el objeto URL ya fue creado.
        return JsonResponse({'status': 'error', 'message': f'Error al procesar la imagen: {e}'}, status=400)

    # PASO 5: Retornar la respuesta
    return JsonResponse({
      'status': 'success',
      'message': 'URL creada correctamente',
      'url': {
        'id': url_obj.id,
        'nombre': url_obj.nombre,
        'url': url_obj.url,
        'area_nombre': url_obj.area.nombre
      }
    }, status=201)

  except ValidationError as e:
    return JsonResponse({'status': 'error', 'message': str(e)}, status=400)
  except Exception as e:
    return JsonResponse({'status': 'error', 'message': f'Error en el servidor: {str(e)}'}, status=500)
  
# ----------------------------- #
# ENDPOINT POST (UPDATE) #
# ----------------------------- #
@csrf_exempt
@require_http_methods(["POST"]) 
def update_url(request, url_id):
  """
  Actualiza una URL existente. Acepta FormData (POST) para
  poder manejar tanto campos de texto como la actualización de la imagen.
  """
  try:
    url_obj = get_object_or_404(Url, id=url_id)
    data = request.POST # Datos de texto
    files = request.FILES # Archivos

    # 1. Actualizar campos de texto
    url_obj.nombre = data.get('nombre', url_obj.nombre)
    url_obj.url = data.get('url', url_obj.url)
    url_obj.descrip = data.get('descrip', url_obj.descrip)
    url_obj.tipo = data.get('tipo', url_obj.tipo)

    # 2. Actualizar Área
    area_id = data.get('area_id')
    if area_id:
      try:
        area = Area.objects.get(id=area_id)
        url_obj.area = area
      except Area.DoesNotExist:
        return JsonResponse({'status': 'error', 'message': 'Área no encontrada'}, status=404)
        
        # 🌟 INICIO CAMBIO: Lógica para manejar la ELIMINACIÓN de imagen si no se envía un archivo nuevo
        
        # 3. Manejo de la Imagen
        
        # Opcion A: Se envió un archivo nuevo (reemplazo o adición)
    if 'img_descrip' in files:
      image_file = files['img_descrip']
      
      # 3a. Borrar la imagen antigua, si existe
      if url_obj.img_descrip:
        try:
          fs = FileSystemStorage()
          old_path = f"informes/{url_obj.img_descrip}"
          if fs.exists(old_path):
            fs.delete(old_path)
        except Exception as e:
          # Esto solo es un mensaje de depuración, no debe interrumpir la respuesta JSON.
          print(f"Error al borrar imagen antigua: {e}") 


      # 3b. Procesar y guardar la nueva imagen 
      try:
        img = Image.open(image_file)
        img.verify()
        img = Image.open(image_file)
        if img.mode in ('RGBA', 'P'):
          img = img.convert('RGB')
        img.thumbnail((1000, 1000))
        thumb_io = BytesIO()
        img.save(thumb_io, format='JPEG', quality=85)
        thumb_file = ContentFile(thumb_io.getvalue())
        fs = FileSystemStorage()
        
        # Usar el mismo nombre de archivo basado en el ID
        filename_base = f"Informe-{url_obj.id}"
        save_path = f"informes/{filename_base}.jpg"
        
        # 🌟 ELIMINADA LA LÍNEA DE ERROR DE SINTAXIS
        
        if fs.exists(save_path):
          fs.delete(save_path)
        
        filename = fs.save(save_path, thumb_file)
        img_db_name = os.path.basename(filename)
        url_obj.img_descrip = img_db_name # Actualizar el campo
      
      except Exception as e:
        return JsonResponse({'status': 'error', 'message': f'Error al procesar la nueva imagen: {e}'}, status=400)
        
        # Opción B: Si no se envió un archivo, comprobamos si la intención fue ELIMINAR.
        # Esto asume que el frontend, al borrar la preview, envía el campo 'img_descrip' vacío en data,
        # o que envías un flag 'remove_img_descrip'. Aquí usamos la opción más simple y probable:
        # no hay archivo en 'files' y el campo de texto asociado al file input está vacío en 'data' (aunque no siempre se envía).
        # Para simplificar, revisaremos si NO se envía un archivo y NO se está manteniendo la imagen existente.
        # *Si el frontend no tiene lógica para enviar un flag, este paso es insuficiente.*
        
    elif 'img_descrip' not in files and data.get('remove_img_descrip') == 'true': 
            # 🌟 CAMBIO DE CÓDIGO 1: Lógica para ELIMINAR la imagen si el frontend envía un flag 'remove_img_descrip=true'
            # (Necesitarás asegurarte de que tu JS envíe este flag al presionar el botón de eliminación en el form).
            if url_obj.img_descrip:
                try:
                    fs = FileSystemStorage()
                    old_path = f"informes/{url_obj.img_descrip}"
                    if fs.exists(old_path):
                        fs.delete(old_path)
                    url_obj.img_descrip = ''  # Borrar referencia en DB
                except Exception as e:
                    print(f"Error al borrar imagen: {e}") 

    # 4. Guardar todos los cambios
    url_obj.save()
        # 🌟 FIN CAMBIO
        

    # 🌟 CORREGIDO: Asegurar que se devuelve un diccionario válido a JsonResponse
    return JsonResponse({
      'status': 'success',
      'message': 'URL actualizada correctamente',
      'url': {
        'id': url_obj.id,
        'nombre': url_obj.nombre,
        'url': url_obj.url,
        'descrip': url_obj.descrip,
        'area_id': url_obj.area.id if url_obj.area else None, # Ajuste para asegurar que área existe
        'area_nombre': url_obj.area.nombre if url_obj.area else 'N/A', # Ajuste para asegurar que área existe
        # Si img_descrip_url es una propiedad, estará correcta. Si se actualizó/eliminó, se reflejará.
        'img_descrip_url': f"{settings.MEDIA_URL}informes/{url_obj.img_descrip}" if url_obj.img_descrip else None,
      }
    }, status=200)

  except Exception as e:
    return JsonResponse({'status': 'error', 'message': f'Error en el servidor: {str(e)}'}, status=500)


@csrf_exempt
@require_http_methods(["DELETE"])
def delete_url(request, url_id):
  """
  Elimina una URL por su ID y su archivo de imagen asociado.
  """
  try:
    # Usamos url_id, por lo que el warning en el código original estaba mal.
    url_obj = get_object_or_404(Url, id=url_id) 
    
    # Eliminar el archivo de imagen del disco
    if url_obj.img_descrip:
      try:
        fs = FileSystemStorage()
        
        # Reconstruir la ruta relativa del archivo
        relative_path = f"informes/{url_obj.img_descrip}"
        
        if fs.exists(relative_path):
          fs.delete(relative_path)
      except Exception as e:
        print(f"Error al eliminar archivo de imagen: {e}") 

    url_obj.delete()
    return JsonResponse({'status': 'success', 'message': 'URL eliminada correctamente'}, status=200)
  except Exception as e:
    return JsonResponse({'status': 'error', 'message': str(e)}, status=500)

@csrf_exempt 
@require_http_methods(["GET"])
def get_url_details(request, url_id):
    try:

        url_obj = Url.objects.select_related('area').get(id=url_id)
        response_data = {
            'id': url_obj.id,
            'nombre': url_obj.nombre,
            'url': url_obj.url,
            'descrip': url_obj.descrip,
            'tipo': url_obj.tipo,
            # 🌟 CAMBIO CRÍTICO: Cálculo explícito de la URL de la imagen
            # (A diferencia de un Serializer o @property que lo harían automáticamente)
            'img_descrip_url': f"{settings.MEDIA_URL}informes/{url_obj.img_descrip}" if url_obj.img_descrip else None,
            
            'area_id': url_obj.area.id if url_obj.area else None,
            'area_nombre': url_obj.area.nombre if url_obj.area else 'N/A',
        }

        # 3. Devolver la respuesta JSON
        return JsonResponse({
            'status': 'success',
            'message': 'Detalles de URL obtenidos con éxito.',
            'result': response_data
        }, status=200)

    except Url.DoesNotExist:
        return JsonResponse({
            'status': 'error',
            'message': 'URL no encontrada.'
        }, status=404)
    except Exception as e:
        return JsonResponse({
            'status': 'error',
            'message': f'Error interno: {str(e)}'
        }, status=500)