# ------------------- IMPORTS -------------------
import csv
import datetime
import io
from datetime import date, timedelta
from io import BytesIO
import openpyxl  # type: ignore
from xhtml2pdf import pisa  # type: ignore
from django.contrib import messages
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.db.models import Prefetch, Q
from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone
from django.conf import settings
from io import BytesIO
from django.template.loader import get_template
from django.core.files.base import ContentFile
import os
from django.views.generic import ListView
from gestion_usuarios.models import Usuario
from .forms import (
    ActaFirmadaUploadForm, EquipoForm, MantenimientoForm, DepartamentoForm, UbicacionForm,
    CategoriaForm, AsignacionForm, FileUploadForm,
)
from .models import (
    Departamento, Ubicacion, CategoriaEquipo, Equipo, Asignacion,
    Mantenimiento, HistorialMovimiento, ActaConsolidada
)

# ------------------- VISTAS PRINCIPALES -------------------

def home_view(request):
    today = date.today()
    soon_threshold = today + timedelta(days=30)
    expiring_warranties = Equipo.objects.filter(
        garantia_fin__gte=today, garantia_fin__lte=soon_threshold
    ).order_by('garantia_fin')
    expired_warranties = Equipo.objects.filter(
        garantia_fin__lt=today
    ).order_by('-garantia_fin')
    overdue_loans = Asignacion.objects.filter(
        activa=True, fecha_entrega_prevista__lt=today
    ).select_related('equipo', 'usuario').order_by('fecha_entrega_prevista')
    loan_soon_threshold = today + timedelta(days=7)
    upcoming_loans = Asignacion.objects.filter(
        activa=True,
        fecha_entrega_prevista__gte=today,
        fecha_entrega_prevista__lte=loan_soon_threshold
    ).select_related('equipo', 'usuario').order_by('fecha_entrega_prevista')
    context = {
        'titulo_pagina': 'Dashboard de Alertas',
        'expiring_warranties': expiring_warranties,
        'expired_warranties': expired_warranties,
        'overdue_loans': overdue_loans,
        'upcoming_loans': upcoming_loans,
        'today': today,
    }
    return render(request, 'gestion_equipos/home.html', context)

# ------------------- EQUIPOS -------------------

@login_required
def lista_equipos(request):
    query = request.GET.get('q', '')
    estado_filtro = request.GET.get('estado', '')
    current_assignment_prefetch = Prefetch(
        'asignaciones',
        queryset=Asignacion.objects.filter(activa=True).select_related('usuario'),
        to_attr='asignacion_actual'
    )
    equipos_list = Equipo.objects.select_related(
        'categoria', 'Ubicacion'
    ).prefetch_related(
        current_assignment_prefetch
    ).order_by('nombre')
    if query:
        equipos_list = equipos_list.filter(
            Q(nombre__icontains=query) |
            Q(numero_serie__icontains=query) |
            Q(marca__icontains=query) |
            Q(modelo__icontains=query) |
            Q(asignaciones__usuario__nombre__icontains=query) |
            Q(asignaciones__usuario__apellido__icontains=query)
        ).distinct()
    if estado_filtro:
        equipos_list = equipos_list.filter(estado=estado_filtro)
    paginator = Paginator(equipos_list, 15 )
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    context = {
        'equipos': page_obj,
        'query': query,
        'estados_equipo': Equipo.ESTADO_CHOICES,
        'estado_seleccionado': estado_filtro,
    }
    return render(request, 'gestion_equipos/lista_equipos.html', context)

@login_required
def crear_equipo(request):
    if request.method == 'POST':
        form = EquipoForm(request.POST, request.FILES)
        if form.is_valid():
            equipo_guardado = form.save()
            HistorialMovimiento.objects.create(
                usuario=request.user,
                accion=f"Creó el equipo: '{equipo_guardado.nombre}' (ID: {equipo_guardado.pk})"
            )
            messages.success(request, f'¡Equipo "{equipo_guardado.nombre}" creado exitosamente!')
            return redirect('gestion_equipos:lista_equipos')
        else:
            messages.error(request, 'Por favor, corrige los errores mostrados en el formulario.')
    else:
        form = EquipoForm()
    context = {
        'form': form,
        'titulo_pagina': 'Registrar Nuevo Equipo'
    }
    return render(request, 'gestion_equipos/crear_equipo.html', context)

@login_required
def detalle_equipo(request, pk):
    equipo = get_object_or_404(Equipo, pk=pk)
    historial_asignaciones = equipo.asignaciones.select_related('usuario').order_by('-fecha_asignacion')
    ultimo_mantenimiento = equipo.mantenimiento_set.order_by('-fecha_mantenimiento').first()
    asignacion_actual = historial_asignaciones.filter(fecha_devolucion__isnull=True).first()
    today = date.today()
    thirty_days_from_now = today + timedelta(days=30)
    context = {
        'equipo': equipo,
        'asignacion_actual': asignacion_actual,
        'historial_asignaciones': historial_asignaciones,
        'ultimo_mantenimiento': ultimo_mantenimiento,
        'titulo_pagina': f'Hoja de Vida: {equipo.nombre}',
        'today': today,
        'thirty_days_from_now': thirty_days_from_now,
    }
    return render(request, 'gestion_equipos/detalle_equipo.html', context)

@login_required
def editar_equipo(request, pk):
    equipo = get_object_or_404(Equipo.all_objects, pk=pk)
    if request.method == 'POST':
        form = EquipoForm(request.POST, request.FILES, instance=equipo)
        if form.is_valid():
            equipo_editado = form.save()
            HistorialMovimiento.objects.create(
                usuario=request.user,
                accion=f"Editó el equipo: '{equipo_editado.nombre}' (ID: {equipo_editado.pk})"
            )
            messages.success(request, f'¡Equipo "{equipo_editado.nombre}" actualizado exitosamente!')
            return redirect('gestion_equipos:detalle_equipo', pk=equipo_editado.pk)
        else:
            messages.error(request, 'Por favor, corrige los errores mostrados en el formulario.')
    else:
        form = EquipoForm(instance=equipo)
    context = {
        'form': form,
        'equipo': equipo,
        'titulo_pagina': f'Editar Equipo: {equipo.nombre}'
    }
    return render(request, 'gestion_equipos/crear_equipo.html', context)

@login_required
def eliminar_equipo(request, pk):
    equipo = get_object_or_404(Equipo.all_objects, pk=pk)
    if request.method == 'POST':
        nombre_equipo = equipo.nombre
        HistorialMovimiento.objects.create(
            usuario=request.user,
            accion=f"Dio de baja (soft delete) al equipo: '{nombre_equipo}' (ID: {equipo.pk})"
        )
        equipo.delete()
        messages.success(request, f'El equipo "{nombre_equipo}" ha sido dado de baja correctamente.')
        return redirect('gestion_equipos:lista_equipos')
    context = {
        'equipo': equipo,
        'titulo_pagina': f'Confirmar Baja de {equipo.nombre}'
    }
    return render(request, 'gestion_equipos/eliminar_confirm.html', context)

@user_passes_test(lambda u: u.is_superuser)
def eliminar_equipo_permanente(request, pk):
    equipo = get_object_or_404(Equipo.all_objects, pk=pk)
    if request.method == 'POST':
        nombre_equipo = equipo.nombre
        numero_serie = equipo.numero_serie
        equipo.delete(force_delete=True)
        HistorialMovimiento.objects.create(
            usuario=request.user,
            accion=f"Eliminó PERMANENTEMENTE el equipo: '{nombre_equipo}' (N/S: {numero_serie})"
        )
        messages.success(request, f'El equipo "{nombre_equipo}" ha sido eliminado permanentemente.')
        return redirect('gestion_equipos:papelera_de_reciclaje')
    context = {
        'equipo': equipo,
        'titulo_pagina': f'Confirmar Eliminación Permanente de {equipo.nombre}'
    }
    return render(request, 'gestion_equipos/eliminar_permanente_confirm.html', context)

# ------------------- MANTENIMIENTOS -------------------

@login_required
def listar_mantenimientos(request):
    mantenimientos_list = Mantenimiento.objects.all().order_by('-fecha_mantenimiento')
    paginator = Paginator(mantenimientos_list, 15)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    context = {
        'mantenimientos': page_obj,
        'titulo_pagina': 'Historial de Mantenimientos'
    }
    return render(request, 'gestion_equipos/listar_mantenimientos.html', context)

@login_required
def crear_mantenimiento(request):
    if request.method == 'POST':
        form = MantenimientoForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'Mantenimiento creado correctamente.')
            return redirect('gestion_equipos:listar_mantenimientos')
        else:
            messages.error(request, 'Error al crear el mantenimiento. Por favor, corrige los errores.')
    else:
        form = MantenimientoForm()
    context = {'form': form}
    return render(request, 'gestion_equipos/crear_mantenimiento.html', context)

@login_required
def detalle_mantenimiento(request, pk):
    mantenimiento = get_object_or_404(Mantenimiento, pk=pk)
    context = {'mantenimiento': mantenimiento}
    return render(request, 'gestion_equipos/detalle_mantenimiento.html', context)

@login_required
def editar_mantenimiento(request, pk):
    mantenimiento = get_object_or_404(Mantenimiento, pk=pk)
    if request.method == 'POST':
        form = MantenimientoForm(request.POST, instance=mantenimiento)
        if form.is_valid():
            form.save()
            messages.success(request, 'Mantenimiento actualizado correctamente.')
            return redirect('gestion_equipos:detalle_mantenimiento', pk=mantenimiento.pk)
        else:
            messages.error(request, 'Error al actualizar el mantenimiento. Por favor, corrige los errores.')
    else:
        form = MantenimientoForm(instance=mantenimiento)
    context = {'form': form, 'mantenimiento': mantenimiento}
    return render(request, 'gestion_equipos/editar_mantenimiento.html', context)

@login_required
def eliminar_mantenimiento(request, pk):
    mantenimiento = get_object_or_404(Mantenimiento, pk=pk)
    if request.method == 'POST':
        mantenimiento.delete()
        messages.success(request, 'Mantenimiento eliminado correctamente.')
        return redirect('gestion_equipos:listar_mantenimientos')
    context = {'mantenimiento': mantenimiento}
    return render(request, 'gestion_equipos/eliminar_mantenimiento.html', context)

# ------------------- CATEGORÍAS, UBICACIONES Y DEPARTAMENTOS -------------------

@login_required
def listar_categorias(request):
    categorias = CategoriaEquipo.objects.all().order_by('nombre')
    context = {'categorias': categorias, 'titulo_pagina': 'Lista de Categorías'}
    return render(request, 'gestion_equipos/categoria_list.html', context)

@login_required
def crear_categoria(request):
    if request.method == 'POST':
        form = CategoriaForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, '¡Categoría creada correctamente!')
            return redirect('gestion_equipos:listar_categorias')
    else:
        form = CategoriaForm()
    context = {'form': form, 'titulo_pagina': 'Crear Nueva Categoría'}
    return render(request, 'gestion_equipos/categoria_form.html', context)

@login_required
def editar_categoria(request, pk):
    categoria = get_object_or_404(CategoriaEquipo, pk=pk)
    if request.method == 'POST':
        form = CategoriaForm(request.POST, instance=categoria)
        if form.is_valid():
            form.save()
            messages.success(request, '¡Categoría actualizada correctamente!')
            return redirect('gestion_equipos:listar_categorias')
    else:
        form = CategoriaForm(instance=categoria)
    context = {'form': form, 'object': categoria, 'titulo_pagina': f'Editar Categoría: {categoria.nombre}'}
    return render(request, 'gestion_equipos/categoria_form.html', context)

@login_required
def eliminar_categoria(request, pk):
    categoria = get_object_or_404(CategoriaEquipo, pk=pk)
    if request.method == 'POST':
        categoria.delete()
        messages.success(request, '¡Categoría eliminada correctamente!')
        return redirect('gestion_equipos:listar_categorias')
    context = {'object': categoria, 'titulo_pagina': 'Confirmar Eliminación'}
    return render(request, 'gestion_equipos/categoria_confirm_delete.html', context)

@login_required
def listar_ubicaciones(request):
    ubicaciones = Ubicacion.objects.all().order_by('nombre')
    context = {'ubicaciones': ubicaciones, 'titulo_pagina': 'Lista de Ubicaciones'}
    return render(request, 'gestion_equipos/ubicacion_list.html', context)

@login_required
def crear_ubicacion(request):
    if request.method == 'POST':
        form = UbicacionForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, '¡Ubicación creada correctamente!')
            return redirect('gestion_equipos:listar_ubicaciones')
    else:
        form = UbicacionForm()
    context = {'form': form, 'titulo_pagina': 'Crear Nueva Ubicación'}
    return render(request, 'gestion_equipos/ubicacion_form.html', context)

@login_required
def editar_ubicacion(request, pk):
    ubicacion = get_object_or_404(Ubicacion, pk=pk)
    if request.method == 'POST':
        form = UbicacionForm(request.POST, instance=ubicacion)
        if form.is_valid():
            form.save()
            messages.success(request, '¡Ubicación actualizada correctamente!')
            return redirect('gestion_equipos:listar_ubicaciones')
    else:
        form = UbicacionForm(instance=ubicacion)
    context = {'form': form, 'object': ubicacion, 'titulo_pagina': f'Editar Ubicación: {ubicacion.nombre}'}
    return render(request, 'gestion_equipos/ubicacion_form.html', context)

@login_required
def eliminar_ubicacion(request, pk):
    ubicacion = get_object_or_404(Ubicacion, pk=pk)
    if request.method == 'POST':
        ubicacion.delete()
        messages.success(request, '¡Ubicación eliminada correctamente!')
        return redirect('gestion_equipos:listar_ubicaciones')
    context = {'object': ubicacion, 'titulo_pagina': 'Confirmar Eliminación'}
    return render(request, 'gestion_equipos/ubicacion_confirm_delete.html', context)

@login_required
def listar_departamentos(request):
    departamentos = Departamento.objects.all().order_by('nombre')
    context = {'departamentos': departamentos, 'titulo_pagina': 'Lista de Departamentos'}
    return render(request, 'gestion_equipos/departamento_list.html', context)

@login_required
def crear_departamento(request):
    if request.method == 'POST':
        form = DepartamentoForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, '¡Departamento creado correctamente!')
            return redirect('gestion_equipos:listar_departamentos')
    else:
        form = DepartamentoForm()
    context = {'form': form, 'titulo_pagina': 'Crear Nuevo Departamento'}
    return render(request, 'gestion_equipos/departamento_form.html', context)

@login_required
def editar_departamento(request, pk):
    departamento = get_object_or_404(Departamento, pk=pk)
    if request.method == 'POST':
        form = DepartamentoForm(request.POST, instance=departamento)
        if form.is_valid():
            form.save()
            messages.success(request, '¡Departamento actualizado correctamente!')
            return redirect('gestion_equipos:listar_departamentos')
    else:
        form = DepartamentoForm(instance=departamento)
    context = {'form': form, 'object': departamento, 'titulo_pagina': f'Editar Departamento: {departamento.nombre}'}
    return render(request, 'gestion_equipos/departamento_form.html', context)

@login_required
def eliminar_departamento(request, pk):
    departamento = get_object_or_404(Departamento, pk=pk)
    if request.method == 'POST':
        departamento.delete()
        messages.success(request, '¡Departamento eliminado correctamente!')
        return redirect('gestion_equipos:listar_departamentos')
    context = {'object': departamento, 'titulo_pagina': 'Confirmar Eliminación'}
    return render(request, 'gestion_equipos/departamento_confirm_delete.html', context)

# ------------------- ASIGNACIONES -------------------

@login_required
def asignar_equipo(request, equipo_pk):
    equipo = get_object_or_404(Equipo, pk=equipo_pk)
    if equipo.estado != 'DI':
        messages.error(request, f"El equipo '{equipo.nombre}' no está disponible para ser asignado.")
        return redirect('gestion_equipos:detalle_equipo', pk=equipo.pk)
    if request.method == 'POST':
        form = AsignacionForm(request.POST)
        if form.is_valid():
            Asignacion.objects.filter(equipo=equipo, activa=True).update(
                activa=False,
                fecha_devolucion=timezone.now()
            )
            nueva_asignacion = form.save(commit=False)
            nueva_asignacion.equipo = equipo
            nueva_asignacion.save()
            equipo.estado = 'AS'
            equipo.save()
            messages.success(request, f"Equipo '{equipo.nombre}' asignado a {nueva_asignacion.usuario.nombre} correctamente.")
            return redirect('gestion_equipos:detalle_equipo', pk=equipo.pk)
    else:
        form = AsignacionForm()
    context = {
        'form': form,
        'equipo': equipo,
        'titulo_pagina': f'Asignar {equipo.nombre}'
    }
    return render(request, 'gestion_equipos/asignar_form.html', context)

@login_required
def devolver_equipo(request, asignacion_pk):
    asignacion = get_object_or_404(Asignacion, pk=asignacion_pk, activa=True)
    if request.method == 'POST':
        asignacion.activa = False
        asignacion.fecha_devolucion = timezone.now()
        asignacion.save()
        equipo = asignacion.equipo
        equipo.estado = 'DI'
        equipo.save()
        messages.success(request, f'Equipo "{equipo.nombre}" devuelto correctamente.')
        return redirect('gestion_equipos:detalle_equipo', pk=equipo.pk)
    context = {'asignacion': asignacion, 'titulo_pagina': 'Confirmar Devolución'}
    return render(request, 'gestion_equipos/devolver_confirm.html', context)

class AsignacionListView(LoginRequiredMixin, ListView):
    model = Asignacion
    template_name = 'gestion_equipos/lista_asignaciones.html'
    context_object_name = 'asignaciones'
    paginate_by = 15

    def get_queryset(self):
        query = self.request.GET.get('q', '')
        queryset = Asignacion.objects.filter(activa=True).select_related(
            'equipo', 'usuario'
        ).order_by('-fecha_asignacion')
        if query:
            queryset = queryset.filter(
                Q(equipo__nombre__icontains=query) |
                Q(equipo__numero_serie__icontains=query) |
                Q(usuario__nombre__icontains=query) |
                Q(usuario__apellido__icontains=query)
            ).distinct()
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['query'] = self.request.GET.get('q', '')
        return context

# ------------------- HISTORIAL Y REPORTES -------------------

@user_passes_test(lambda u: u.is_superuser)
def ver_historial_movimientos(request):
    historial_list = HistorialMovimiento.objects.select_related('usuario').all()
    paginator = Paginator(historial_list, 20)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    context = {'historial': page_obj, 'titulo_pagina': 'Historial de Movimientos'}
    return render(request, 'gestion_equipos/historial_movimientos.html', context)

@login_required
def generar_reportes(request):
    report_type = request.GET.get('report_type', 'mantenimientos')
    fecha_inicio_str = request.GET.get('fecha_inicio')
    fecha_fin_str = request.GET.get('fecha_fin')
    export_format = request.GET.get('export')
    
    # --- Lógica unificada para procesar fechas (CORREGIDO) ---
    fecha_inicio, fecha_fin = None, None
    if fecha_inicio_str:
        # Se usa datetime.datetime.strptime para corregir el AttributeError
        fecha_inicio = datetime.datetime.strptime(fecha_inicio_str, '%Y-%m-%d').date()
    if fecha_fin_str:
        fecha_fin = datetime.datetime.strptime(fecha_fin_str, '%Y-%m-%d').date()

    # Contexto inicial para la plantilla
    context = {
        'titulo_pagina': 'Generar Reportes',
        'report_type_selected': report_type,
        'fecha_inicio_seleccionada': fecha_inicio_str or '',
        'fecha_fin_seleccionada': fecha_fin_str or '',
    }

    # --- Lógica para reportes de MANTENIMIENTO ---
    if report_type == 'mantenimientos':
        mantenimientos_filtrados = Mantenimiento.objects.select_related('equipo').order_by('-fecha_mantenimiento')
        
        # Aplicar filtros de fecha si existen
        if fecha_inicio:
            mantenimientos_filtrados = mantenimientos_filtrados.filter(fecha_mantenimiento__gte=fecha_inicio)
        if fecha_fin:
            mantenimientos_filtrados = mantenimientos_filtrados.filter(fecha_mantenimiento__lte=fecha_fin)
            
        # Si se solicita exportar...
        if export_format == 'xlsx':
            headers = ['ID Mantenimiento', 'Equipo', 'N° Serie Equipo', 'Tipo', 'Descripción', 'Fecha', 'Técnico']
            data_rows = []
            for m in mantenimientos_filtrados:
                data_rows.append([
                    m.id,
                    m.equipo.nombre,
                    m.equipo.numero_serie if m.equipo else '',
                    # CORRECCIÓN: Se accede directamente al campo de texto
                    m.tipo_mantenimiento,
                    m.descripcion,
                    m.fecha_mantenimiento.strftime('%Y-%m-%d'),
                    m.tecnico
                ])
            
            wb = openpyxl.Workbook()
            ws = wb.active
            ws.title = "Reporte Mantenimientos"
            ws.append(headers)
            for row in data_rows:
                ws.append(row)
            
            output = BytesIO()
            wb.save(output)
            output.seek(0)
            
            response = HttpResponse(
                output,
                content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            )
            response['Content-Disposition'] = f'attachment; filename="reporte_mantenimientos_{date.today().isoformat()}.xlsx"'
            return response

        context['mantenimientos_reporte'] = mantenimientos_filtrados

    # --- Lógica para reportes de EQUIPOS ---
    elif report_type == 'equipos':
        current_assignment_prefetch = Prefetch(
            'asignaciones',
            queryset=Asignacion.objects.filter(activa=True).select_related('usuario'),
            to_attr='asignacion_actual'
        )
        equipos_filtrados = Equipo.objects.select_related(
            'categoria', 
            'Ubicacion'
        ).prefetch_related(current_assignment_prefetch).order_by('nombre')
        
        if export_format == 'xlsx':
            headers = [
                'ID', 'Nombre', 'N° Serie', 'Estado', 'Categoría', 'Ubicación', 
                'Usuario Asignado', 'Fecha Asignación', 'Marca Mouse', 'Serial Mouse', 
                'Marca Teclado', 'Serial Teclado', 'Marca Monitor', 'Modelo Monitor', 'Serial Monitor'
            ]
            data_rows = []
            for equipo in equipos_filtrados:
                usuario_asignado = "No asignado"
                fecha_asignacion = ""
                if hasattr(equipo, 'asignacion_actual') and equipo.asignacion_actual:
                    asignacion = equipo.asignacion_actual[0]
                    usuario_asignado = f"{asignacion.usuario.nombre} {asignacion.usuario.apellido}"
                    fecha_asignacion = asignacion.fecha_asignacion.strftime('%Y-%m-%d') if asignacion.fecha_asignacion else ""
                
                data_rows.append([
                    equipo.id, equipo.nombre, equipo.numero_serie, equipo.get_estado_display(),
                    equipo.categoria.nombre if equipo.categoria else '',
                    equipo.Ubicacion.nombre if equipo.Ubicacion else '',
                    usuario_asignado, fecha_asignacion,
                    equipo.mouse_marca or 'N/A', equipo.mouse_serial or 'N/A',
                    equipo.teclado_marca or 'N/A', equipo.teclado_serial or 'N/A',
                    equipo.monitor_marca or 'N/A', equipo.monitor_modelo or 'N/A', equipo.monitor_serial or 'N/A',
                ])
            
            wb = openpyxl.Workbook()
            ws = wb.active
            ws.title = "Reporte Equipos"
            ws.append(headers)
            for row in data_rows:
                ws.append(row)
            
            output = BytesIO()
            wb.save(output)
            output.seek(0)
            
            response = HttpResponse(
                output,
                content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            )
            response['Content-Disposition'] = f'attachment; filename="reporte_equipos_{date.today().isoformat()}.xlsx"'
            return response

        context['equipos_reporte'] = equipos_filtrados
    
    # Renderiza la plantilla HTML con los datos correspondientes para la vista en web
    return render(request, 'gestion_equipos/generar_reportes.html', context)

# ------------------- IMPORTACIÓN Y PLANTILLAS -------------------

@user_passes_test(lambda u: u.is_superuser)
def importar_equipos_masivamente(request):
    if request.method == 'POST':
        form = FileUploadForm(request.POST, request.FILES)
        if form.is_valid():
            csv_file = request.FILES['file']
            if not csv_file.name.endswith('.csv'):
                messages.error(request, '¡Error! El archivo debe tener formato .csv')
            else:
                try:
                    decoded_file = csv_file.read().decode('utf-8-sig')
                    io_string = io.StringIO(decoded_file)
                    reader = csv.DictReader(io_string, delimiter=';')
                    equipos_creados, equipos_actualizados, log_errores = 0, 0, []
                    for i, row in enumerate(reader, 2):
                        numero_serie = row.get('numero_serie', '').strip()
                        if not numero_serie:
                            log_errores.append(f"Fila {i}: Falta el número de serie, que es obligatorio.")
                            continue
                        try:
                            data = {
                                'nombre': row.get('nombre', '').strip(),
                                'marca': row.get('marca', '').strip(),
                                'modelo': row.get('modelo', '').strip(),
                                'notas': row.get('notas', '').strip(),
                                'disco_duro_tipo': row.get('disco_duro_tipo', '').strip(),
                                'disco_duro_capacidad_gb': int(row['disco_duro_capacidad_gb']) if row.get('disco_duro_capacidad_gb') else None,
                                'procesador_marca': row.get('procesador_marca', '').strip(),
                                'procesador_tipo': row.get('procesador_tipo', '').strip(),
                                'procesador_velocidad_ghz': float(row['procesador_velocidad_ghz'].replace(',', '.')) if row.get('procesador_velocidad_ghz') else None,
                                'ram_cantidad_gb': int(row['ram_cantidad_gb']) if row.get('ram_cantidad_gb') else None,
                                'ram_tipo': row.get('ram_tipo', '').strip(),
                                'teclado_marca': row.get('teclado_marca', '').strip(),
                                'teclado_serial': row.get('teclado_serial', '').strip(),
                                'mouse_marca': row.get('mouse_marca', '').strip(),
                                'mouse_serial': row.get('mouse_serial', '').strip(),
                                'monitor_marca': row.get('monitor_marca', '').strip(),
                                'monitor_modelo': row.get('monitor_modelo', '').strip(),
                                'monitor_serial': row.get('monitor_serial', '').strip(),
                            }
                            categoria_nombre = row.get('categoria', '').strip()
                            if categoria_nombre:
                                categoria, _ = CategoriaEquipo.objects.get_or_create(nombre=categoria_nombre)
                                data['categoria'] = categoria
                            ubicacion_nombre = row.get('Ubicacion', '').strip()
                            if ubicacion_nombre:
                                ubicacion, _ = Ubicacion.objects.get_or_create(nombre=ubicacion_nombre)
                                data['Ubicacion'] = ubicacion
                            fecha_str = row.get('fecha_adquisicion', '').strip()
                            if fecha_str: data['fecha_adquisicion'] = fecha_str
                            obj, created = Equipo.objects.update_or_create(numero_serie=numero_serie, defaults=data)
                            usuario_email = row.get('usuario_email', '').strip()
                            Asignacion.objects.filter(equipo=obj, activa=True).update(activa=False, fecha_devolucion=timezone.now())
                            if usuario_email:
                                try:
                                    usuario = Usuario.objects.get(email__iexact=usuario_email)
                                    Asignacion.objects.create(equipo=obj, usuario=usuario, activa=True)
                                    obj.estado = 'AS'
                                except Usuario.DoesNotExist:
                                    log_errores.append(f"Fila {i}: El usuario con email '{usuario_email}' no existe. El equipo se dejó como Disponible.")
                                    obj.estado = 'DI'
                            else:
                                obj.estado = 'DI'
                            obj.save()
                            if created: equipos_creados += 1
                            else: equipos_actualizados += 1
                        except Exception as e:
                            log_errores.append(f"Fila {i} (N/S: {numero_serie}): {e}")
                    if not log_errores:
                        messages.success(request, f'¡Carga completada! Equipos creados: {equipos_creados}, Actualizados: {equipos_actualizados}.')
                    else:
                        messages.warning(request, f'Carga finalizada. Creados: {equipos_creados}, Actualizados: {equipos_actualizados}, Errores: {len(log_errores)}.')
                        for error in log_errores[:5]: messages.error(request, error)
                    HistorialMovimiento.objects.create(usuario=request.user, accion=f"Carga masiva de equipos. Creados: {equipos_creados}, Actualizados: {equipos_actualizados}, Errores: {len(log_errores)}.")
                except Exception as e:
                    messages.error(request, f"Error crítico al procesar el archivo: {e}")
            return redirect('gestion_equipos:importar_equipos')
    else:
        form = FileUploadForm()
    context = { 'form': form, 'titulo_pagina': 'Carga Masiva de Equipos' }
    return render(request, 'gestion_equipos/importar_equipos.html', context)

def descargar_plantilla_csv(request):
    response = HttpResponse(content_type='text/csv', headers={'Content-Disposition': 'attachment; filename="plantilla_equipos.csv"'})
    response.write(u'\ufeff'.encode('utf8'))
    writer = csv.writer(response, delimiter=';')
    headers = [
        'nombre', 'numero_serie', 'marca', 'modelo', 'estado', 'categoria', 'Ubicacion',
        'fecha_adquisicion', 'notas', 'disco_duro_tipo', 'disco_duro_capacidad_gb',
        'procesador_marca', 'procesador_tipo', 'procesador_velocidad_ghz', 'ram_cantidad_gb',
        'ram_tipo', 'teclado_marca', 'teclado_serial', 'mouse_marca', 'mouse_serial',
        'monitor_marca', 'monitor_modelo', 'monitor_serial', 'usuario_email'
    ]
    writer.writerow(headers)
    example_row = [
        'PC de Ejemplo', 'PC-EJ-001', 'Dell', 'Optiplex', 'DI', 'Computador de Mesa',
        'Oficina Principal', '2025-07-17', 'Equipo de prueba', 'SSD', '512', 'Intel',
        'Core i5', '3.2', '16', 'DDR4', 'Logitech', 'SN-TEC-01', 'Logitech', 'SN-MOU-01',
        'Dell', 'P2419H', 'SN-MON-01', 'usuario@ejemplo.com'
    ]
    writer.writerow(example_row)
    return response

# ------------------- PAPELERA Y RESTAURACIÓN -------------------

@user_passes_test(lambda u: u.is_superuser)
def papelera_de_reciclaje(request):
    equipos_inactivos = Equipo.all_objects.filter(activo=False).order_by('-nombre')
    context = {'equipos_inactivos': equipos_inactivos, 'titulo_pagina': 'Papelera de Reciclaje de Equipos'}
    return render(request, 'gestion_equipos/papelera.html', context)

@user_passes_test(lambda u: u.is_superuser)
def restaurar_equipo(request, pk):
    equipo = get_object_or_404(Equipo.all_objects, pk=pk)
    if request.method == 'POST':
        equipo.activo = True
        equipo.estado = 'DI'
        equipo.save()
        HistorialMovimiento.objects.create(
            usuario=request.user,
            accion=f"Restauró el equipo: '{equipo.nombre}' (ID: {equipo.pk})"
        )
        messages.success(request, f'El equipo "{equipo.nombre}" ha sido restaurado exitosamente.')
        return redirect('gestion_equipos:papelera_de_reciclaje')
    return redirect('gestion_equipos:papelera_de_reciclaje')

@login_required
def link_callback(uri, rel):
    static_root = getattr(settings, 'STATIC_ROOT', settings.STATICFILES_DIRS[0])
    path = os.path.join(static_root, uri.replace(settings.STATIC_URL, ""))
    if not os.path.isfile(path):
        return None
    return path

def generar_acta_consolidada_pdf(request, usuario_pk):
    usuario = get_object_or_404(Usuario, pk=usuario_pk)
    asignaciones_activas = Asignacion.objects.filter(usuario=usuario, activa=True).select_related('equipo')

    # --- LÓGICA CLAVE: OBTENER LA RUTA ABSOLUTA DEL MEMBRETE ---
    # Esto asume que tienes 'static/img/Hoja_membrete.png' en tu proyecto
    # y que STATICFILES_DIRS está configurado en settings.py
    try:
        # Construye la ruta completa al archivo de imagen
        membrete_path = os.path.join(settings.STATICFILES_DIRS[0], 'img/Hoja_membrete.png')
    except (IndexError, AttributeError):
        # Si hay un problema, se deja la ruta vacía para que no dé error
        membrete_path = ''

    context = {
        'usuario': usuario,
        'asignaciones_activas': asignaciones_activas,
        'usuario_entrega': request.user,
        'fecha_generacion': timezone.now(),
        'membrete_path': membrete_path, # Se pasa la ruta a la plantilla
    }

    template = get_template('gestion_equipos/acta_consolidada_template.html')
    html = template.render(context)

    # --- LÓGICA COMPLETADA PARA GENERAR Y GUARDAR EL PDF ---
    buffer = BytesIO()
    pisa_status = pisa.CreatePDF(html, dest=buffer)
    if pisa_status.err:
       messages.error(request, 'Hubo un error al generar el PDF.')
       return redirect('gestion_usuarios:detalle_usuario', pk=usuario.pk)
    
    buffer.seek(0)

    # Crear el identificador y guardar el acta
    fecha_actual_str = timezone.now().strftime('%Y%m%d-%H%M%S')
    identificador_acta = f"ACTA-{fecha_actual_str}-U{usuario.pk}"
    nombre_archivo = f'{identificador_acta}.pdf'
    
    acta = ActaConsolidada(
        usuario=usuario,
        identificador=identificador_acta
    )
    acta.archivo_generado.save(nombre_archivo, ContentFile(buffer.read()), save=True)
    
    HistorialMovimiento.objects.create(
        usuario=request.user,
        accion=f"Generó y guardó el acta consolidada '{identificador_acta}' para '{usuario.nombre} {usuario.apellido}'"
    )

    messages.success(request, f"Se ha generado y guardado el acta {identificador_acta}.")
    return redirect('gestion_usuarios:detalle_usuario', pk=usuario.pk)

@login_required
def subir_acta_firmada(request, acta_pk):
    acta = get_object_or_404(ActaConsolidada, pk=acta_pk)
    
    if request.method == 'POST':
        form = ActaFirmadaUploadForm(request.POST, request.FILES, instance=acta)
        if form.is_valid():
            form.save() # Guarda el archivo en el registro del acta existente
            
            HistorialMovimiento.objects.create(
                usuario=request.user,
                accion=f"Subió el acta consolidada firmada '{acta.identificador}'"
            )
            
            messages.success(request, 'El acta firmada se ha subido correctamente.')
            return redirect('gestion_usuarios:detalle_usuario', pk=acta.usuario.pk)
    else:
        form = ActaFirmadaUploadForm(instance=acta)

    context = {
        'form': form,
        'acta': acta,
        'titulo_pagina': 'Subir Acta Consolidada Firmada'
    }
    return render(request, 'gestion_equipos/subir_acta_consolidada_form.html', context)

@user_passes_test(lambda u: u.is_superuser)
def listar_actas(request):
    actas = ActaConsolidada.objects.select_related('usuario').all()
    context = {
        'actas': actas,
        'titulo_pagina': 'Gestor de Actas Consolidadas'
    }
    return render(request, 'gestion_equipos/listar_actas.html', context)

@user_passes_test(lambda u: u.is_superuser)
def dar_de_baja_acta(request, acta_pk):
    acta = get_object_or_404(ActaConsolidada.all_objects, pk=acta_pk)
    if request.method == 'POST':
        identificador = acta.identificador
        acta.delete() # Llama al método de soft delete
        HistorialMovimiento.objects.create(
            usuario=request.user,
            accion=f"Dio de baja al acta consolidada: '{identificador}'"
        )
        messages.success(request, f"El acta {identificador} ha sido dada de baja.")
        return redirect('gestion_equipos:listar_actas')
    
    context = { 'acta': acta, 'titulo_pagina': 'Confirmar Baja de Acta' }
    return render(request, 'gestion_equipos/acta_confirm_baja.html', context)