from django.shortcuts import render
from rest_framework import viewsets, status
from rest_framework.decorators import action, api_view
from rest_framework.response import Response
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from django.http import HttpResponse
from datetime import datetime
import csv
import io
from openpyxl import Workbook
from django.db import transaction
from Models.oportunidad_de_venta_model import OportunidadDeVenta
from oportunidad_de_venta.serializers import OportunidadDeVentaSerializer, DeleteOportunidadSerializer, CreateOportunidadSerializer, EditOportunidadSerializer, IncidenciaSerializer
from Models import oportunidad_de_venta_model
from django.utils import timezone
from rest_framework import serializers

class ChangeWorkflowSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=True)
    column_workflow_id = serializers.IntegerField(required=True)

class ExportSerializer(serializers.Serializer):
    fecha = serializers.DateField(required=False, help_text="Fecha única (YYYY-MM-DD)")
    desde = serializers.DateField(required=False, help_text="Fecha desde (YYYY-MM-DD)")
    hasta = serializers.DateField(required=False, help_text="Fecha hasta (YYYY-MM-DD)")
    tipo = serializers.ChoiceField(choices=['csv', 'excel'], default='csv', help_text="Tipo de archivo: 'csv' o 'excel'")

class OportunidadDeVentaViewSet(viewsets.ViewSet):
    @swagger_auto_schema(
        operation_description="Lista todas las oportunidades de venta activas",
        responses={
            200: OportunidadDeVentaSerializer(many=True)
        }
    )
    @action(detail=False, methods=['get'], url_path='list_sales_opportunity')
    def list_sales_opportunity(self, request):
        oportunidades = OportunidadDeVenta.objects.filter(
            deleted_at__isnull=True
        ).select_related(
            'empresa',  'usuario_responsable', 'estado_oportunidad', 'column_workflow'
        )
        serializer = OportunidadDeVentaSerializer(oportunidades, many=True)
        return Response(serializer.data)
    
    @swagger_auto_schema(
        operation_description="Crea una nueva oportunidad de venta. El campo estado_oportunidad_id debe ser un ID existente en la tabla de estados de oportunidad. Consulte el endpoint /api/estado_oportunidad_venta/listar/ para obtener los valores válidos.",
        request_body=CreateOportunidadSerializer,
        responses={
            201: openapi.Response(
                description="Oportunidad creada correctamente",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'mensaje': openapi.Schema(type=openapi.TYPE_STRING, description='Mensaje de éxito'),
                        'id': openapi.Schema(type=openapi.TYPE_INTEGER, description='ID de la oportunidad creada'),
                        'datos': openapi.Schema(type=openapi.TYPE_OBJECT, description='Datos de la oportunidad creada')
                    }
                )
            ),
            400: openapi.Response(
                description="Error en los datos proporcionados",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'error': openapi.Schema(type=openapi.TYPE_STRING),
                        'detalles': openapi.Schema(type=openapi.TYPE_OBJECT)
                    }
                )
            )
        }
    )
    @action(detail=False, methods=['post'], url_path='create')
    @transaction.atomic
    def create_opportunity(self, request):
        serializer = CreateOportunidadSerializer(data=request.data)
        
        if not serializer.is_valid():
            return Response(
                {"error": "Datos inválidos", "detalles": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        productos_data = serializer.validated_data.pop('productos', [])

        # Guardar la oportunidad con fechas
        oportunidad = serializer.save(
            fecha_creacion=timezone.now(),
            fecha_ultima_actualizacion=timezone.now()
        )
        
        if productos_data:
            from producto.models import OportunidadProducto
            for item in productos_data:
                # Se asume que validación de IDs se hizo o se confía, o catch error
                try:
                    OportunidadProducto.objects.create(
                        oportunidad=oportunidad,
                        producto_id=item['producto_id'],
                        cantidad=item.get('cantidad', 1),
                        precio_unitario=item['precio_unitario']
                    )
                except Exception as e:
                    print(f"Error creating product item: {e}")

        # Serializar la respuesta incluyendo workflow_nombre y workflow_id
        data = OportunidadDeVentaSerializer(oportunidad).data
        if oportunidad.column_workflow:
            data['workflow_id'] = oportunidad.column_workflow.id
        else:
            data['workflow_id'] = None
        
        return Response({
            "mensaje": "Oportunidad de venta creada correctamente",
            "id": oportunidad.id,
            "datos": data
        }, status=status.HTTP_201_CREATED)

    @swagger_auto_schema(
        operation_description="Edita una oportunidad de venta existente mediante método POST. Permite actualizar cualquier campo excepto la fecha de creación. Solo es necesario incluir el ID y los campos que se desean modificar.",
        request_body=EditOportunidadSerializer,
        responses={
            # ... (keep existing responses or abbreviations)
            200: openapi.Response(
                description="Oportunidad actualizada correctamente",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'mensaje': openapi.Schema(type=openapi.TYPE_STRING),
                        'id': openapi.Schema(type=openapi.TYPE_INTEGER),
                        'campos_actualizados': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_STRING)),
                        'datos': openapi.Schema(type=openapi.TYPE_OBJECT)
                    }
                )
            ),
            # ... 
        }
    )
    @action(detail=False, methods=['post'], url_path='update')
    @transaction.atomic
    def update_opportunity(self, request):
        serializer = EditOportunidadSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(
                {"error": "Datos inválidos", "detalles": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        try:
            id_oportunidad = serializer.validated_data.pop('id')
            productos_data = serializer.validated_data.pop('productos', None)
            
            oportunidad = OportunidadDeVenta.objects.get(id=id_oportunidad, deleted_at__isnull=True)

            campos_actualizados = []
            for campo, valor in serializer.validated_data.items():
                if campo == 'workflow_id':
                    if oportunidad.column_workflow_id != valor:
                        oportunidad.column_workflow_id = valor
                        campos_actualizados.append('column_workflow_id')
                else:
                    old_value = getattr(oportunidad, campo, None)
                    if old_value != valor:
                        setattr(oportunidad, campo, valor)
                        campos_actualizados.append(campo)

            oportunidad.fecha_ultima_actualizacion = timezone.now()
            oportunidad.save(update_fields=campos_actualizados + ['fecha_ultima_actualizacion'])

            if productos_data is not None:
                from producto.models import OportunidadProducto
                # Delete existing
                OportunidadProducto.objects.filter(oportunidad=oportunidad).delete()
                # Create new
                for item in productos_data:
                     # Add validation for fields being present
                     if 'producto_id' in item:
                        OportunidadProducto.objects.create(
                            oportunidad=oportunidad,
                            producto_id=item['producto_id'],
                            cantidad=item.get('cantidad', 1),
                            precio_unitario=item.get('precio_unitario', 0)
                        )
                campos_actualizados.append('productos')

            # Serializar datos incluyendo workflow_nombre y workflow_id
            data = OportunidadDeVentaSerializer(oportunidad).data
            data['workflow_id'] = oportunidad.column_workflow.id if oportunidad.column_workflow else None

            return Response({
                "mensaje": "Oportunidad de venta actualizada correctamente",
                "id": id_oportunidad,
                "campos_actualizados": campos_actualizados,
                "datos": data
            }, status=status.HTTP_200_OK)

        except OportunidadDeVenta.DoesNotExist:
            return Response(
                {"error": "La oportunidad de venta no existe o ya fue eliminada"},
                status=status.HTTP_404_NOT_FOUND
            )

    @swagger_auto_schema(
        operation_description="Elimina lógicamente una oportunidad de venta por su ID",
        request_body=DeleteOportunidadSerializer,
        responses={
            200: openapi.Response(
                description="Oportunidad eliminada correctamente",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'mensaje': openapi.Schema(type=openapi.TYPE_STRING),
                        'id': openapi.Schema(type=openapi.TYPE_INTEGER)
                    }
                )
            ),
            400: openapi.Response(
                description="Datos inválidos",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'error': openapi.Schema(type=openapi.TYPE_STRING),
                        'detalles': openapi.Schema(type=openapi.TYPE_OBJECT)
                    }
                )
            ),
            404: openapi.Response(
                description="Oportunidad no encontrada",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'error': openapi.Schema(type=openapi.TYPE_STRING)
                    }
                )
            )
        }
    )
    @action(detail=False, methods=['post'], url_path='delete')
    def delete_opportunity(self, request):
        serializer = DeleteOportunidadSerializer(data=request.data)
        
        if not serializer.is_valid():
            return Response({"error": "Datos inválidos", "detalles": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
            
        try:
            id_oportunidad = serializer.validated_data['id']
            oportunidad = OportunidadDeVenta.objects.get(id=id_oportunidad, deleted_at__isnull=True)
            oportunidad.deleted_at = timezone.now()
            oportunidad.save()
            return Response({"mensaje": "Oportunidad de venta eliminada correctamente", "id": id_oportunidad}, status=status.HTTP_200_OK)
        except OportunidadDeVenta.DoesNotExist:
            return Response({"error": "La oportunidad de venta no existe o ya fue eliminada"}, status=status.HTTP_404_NOT_FOUND)

    @swagger_auto_schema(
        operation_description="Lista todas las oportunidades de venta filtradas por workflow_id (column_workflow_id)",
        manual_parameters=[
            openapi.Parameter(
                'workflow_id',
                openapi.IN_QUERY,
                description="ID del workflow (column_workflow_id)",
                type=openapi.TYPE_INTEGER,
                required=True
            )
        ],
        responses={
            200: OportunidadDeVentaSerializer(many=True)
        }
    )
    @action(detail=False, methods=['get'], url_path='by_workflow')
    def list_by_workflow(self, request):
        workflow_id = request.query_params.get('workflow_id')
        if not workflow_id:
            return Response(
                {"error": "workflow_id es requerido"},
                status=status.HTTP_400_BAD_REQUEST
            )
        oportunidades = OportunidadDeVenta.objects.filter(
            column_workflow_id=workflow_id,
            deleted_at__isnull=True
        ).select_related(
            'empresa', 'usuario_responsable', 'estado_oportunidad', 'column_workflow'
        )
        serializer = OportunidadDeVentaSerializer(oportunidades, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

    @swagger_auto_schema(
        operation_description="Cambia el workflow (column_workflow_id) de una oportunidad de venta por su ID.",
        request_body=ChangeWorkflowSerializer,
        responses={
            200: openapi.Response(
                description="Workflow actualizado correctamente",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'mensaje': openapi.Schema(type=openapi.TYPE_STRING),
                        'id': openapi.Schema(type=openapi.TYPE_INTEGER),
                        'column_workflow_id': openapi.Schema(type=openapi.TYPE_INTEGER)
                    }
                )
            ),
            400: openapi.Response(
                description="Datos inválidos",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'error': openapi.Schema(type=openapi.TYPE_STRING),
                        'detalles': openapi.Schema(type=openapi.TYPE_OBJECT)
                    }
                )
            ),
            404: openapi.Response(
                description="Oportunidad no encontrada",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'error': openapi.Schema(type=openapi.TYPE_STRING)
                    }
                )
            )
        }
    )
    @action(detail=False, methods=['post'], url_path='change_workflow')
    def change_workflow(self, request):
        serializer = ChangeWorkflowSerializer(data=request.data)
        if not serializer.is_valid():
            return Response({"error": "Datos inválidos", "detalles": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
        try:
            oportunidad = OportunidadDeVenta.objects.get(id=serializer.validated_data['id'], deleted_at__isnull=True)
            oportunidad.column_workflow_id = serializer.validated_data['column_workflow_id']
            oportunidad.save()
            return Response({
                "mensaje": "Workflow actualizado correctamente",
                "id": oportunidad.id,
                "column_workflow_id": oportunidad.column_workflow_id
            }, status=status.HTTP_200_OK)
        except OportunidadDeVenta.DoesNotExist:
            return Response({"error": "La oportunidad no existe o está eliminada"}, status=status.HTTP_404_NOT_FOUND)


    @swagger_auto_schema(
        operation_description="Exporta oportunidades de venta filtradas por fecha. Envía los parámetros como JSON en el cuerpo de la petición.",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'fecha': openapi.Schema(
                    type=openapi.TYPE_STRING,
                    format=openapi.FORMAT_DATE,
                    description="Fecha única (YYYY-MM-DD). Ejemplo: 2025-10-20",
                    example="2025-10-20"
                ),
                'desde': openapi.Schema(
                    type=openapi.TYPE_STRING,
                    format=openapi.FORMAT_DATE,
                    description="Fecha desde (YYYY-MM-DD). Ejemplo: 2025-10-01",
                    example="2025-10-01"
                ),
                'hasta': openapi.Schema(
                    type=openapi.TYPE_STRING,
                    format=openapi.FORMAT_DATE,
                    description="Fecha hasta (YYYY-MM-DD). Ejemplo: 2025-10-31",
                    example="2025-10-31"
                ),
                'tipo': openapi.Schema(
                    type=openapi.TYPE_STRING,
                    enum=['csv', 'excel'],
                    description="Tipo de archivo de exportación",
                    default='csv',
                    example='excel'
                )
            },
            example={
                "desde": "2025-10-01",
                "hasta": "2025-10-31",
                "tipo": "excel"
            }
        ),
        responses={
            200: openapi.Response(
                description="Archivo exportado correctamente (CSV o Excel)",
                schema=openapi.Schema(type=openapi.TYPE_FILE)
            ),
            400: openapi.Response(
                description="Error en los parámetros o tipo de archivo no soportado",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'error': openapi.Schema(type=openapi.TYPE_STRING),
                        'detalles': openapi.Schema(type=openapi.TYPE_OBJECT)
                    }
                )
            )
        }
    )
    @action(detail=False, methods=['post'], url_path='export')
    def export(self, request):
        serializer = ExportSerializer(data=request.data)
        
        if not serializer.is_valid():
            return Response(
                {"error": "Datos inválidos", "detalles": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # Obtener datos validados
        validated_data = serializer.validated_data
        fecha = validated_data.get('fecha')
        desde = validated_data.get('desde')
        hasta = validated_data.get('hasta')
        tipo = validated_data.get('tipo', 'csv').lower()

        queryset = OportunidadDeVenta.objects.filter(deleted_at__isnull=True)

        # Filtrar por fecha
        if fecha:
            queryset = queryset.filter(fecha_creacion__date=fecha)
        elif desde and hasta:
            queryset = queryset.filter(fecha_creacion__date__range=[desde, hasta])
        elif desde:  # solo "desde" => desde hasta hoy
            queryset = queryset.filter(fecha_creacion__date__gte=desde)
        elif hasta:  # solo "hasta" => desde el inicio hasta "hasta"
            queryset = queryset.filter(fecha_creacion__date__lte=hasta)
        # si no envían nada => trae todo

        queryset = queryset.select_related(
            'empresa', 'usuario_responsable', 'estado_oportunidad', 'column_workflow'
        )

        # Serializar y eliminar deleted_at
        serializer_data = OportunidadDeVentaSerializer(queryset, many=True)
        data = serializer_data.data
        for row in data:
            row.pop('deleted_at', None)

        if tipo == 'csv':
            output = io.StringIO()
            writer = csv.DictWriter(output, fieldnames=data[0].keys() if data else [])
            writer.writeheader()
            for row in data:
                writer.writerow(row)
            filename = f"oportunidades_{fecha or (str(desde)+'_'+str(hasta) if desde and hasta else 'todas')}.csv"
            response = HttpResponse(output.getvalue(), content_type='text/csv')
            response['Content-Disposition'] = f'attachment; filename="{filename}"'
            return response

        elif tipo == 'excel':
            wb = Workbook()
            ws = wb.active
            if data:
                ws.append(list(data[0].keys()))
                for row in data:
                    ws.append(list(row.values()))
            filename = f"oportunidades_{fecha or (str(desde)+'_'+str(hasta) if desde and hasta else 'todas')}.xlsx"
            response = HttpResponse(
                content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            )
            response['Content-Disposition'] = f'attachment; filename="{filename}"'
            wb.save(response)
            return response


    @swagger_auto_schema(
        operation_description="Obtiene notificaciones de oportunidades vencidas o por vencer (7 días) para el usuario actual.",
        responses={
            200: openapi.Response(
                description="Listado de notificaciones",
                schema=openapi.Schema(
                    type=openapi.TYPE_OBJECT,
                    properties={
                        'expired': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_OBJECT)),
                        'expiring_soon': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_OBJECT)),
                        'count': openapi.Schema(type=openapi.TYPE_INTEGER)
                    }
                )
            )
        }
    )
    @action(detail=False, methods=['get'], url_path='notifications')
    def get_notifications(self, request):
        user = None
        if request.user and request.user.is_authenticated:
            user = getattr(request.user, '_user', request.user)
        
        if not user:
             return Response({"error": "Usuario no autenticado"}, status=status.HTTP_401_UNAUTHORIZED)
             
        today = timezone.now().date()
        limit_date = today + timezone.timedelta(days=7)
        
        # Determine if user is admin
        is_admin = False
        if getattr(user, 'is_superuser', False):
            is_admin = True
        # Check by Role ID: 1 = Administrador
        elif hasattr(user, 'rol_usuario_id') and user.rol_usuario_id == 1:
             is_admin = True
        
        # Base Query
        queryset = OportunidadDeVenta.objects.filter(
            deleted_at__isnull=True,
            estado_oportunidad__es_final=False
        ).exclude(
            estado_oportunidad_id=4 
        ).select_related('empresa', 'usuario_responsable') # Added usuario_responsable for better info if needed
        
        # Apply user filter only if NOT admin
        if not is_admin:
            queryset = queryset.filter(usuario_responsable_id=user.id)
        
        # Filter by date range: older than today OR within next 7 days
        from django.db.models import Q
        queryset = queryset.filter(
            Q(fecha_estimada_cierre__lt=today) | 
            Q(fecha_estimada_cierre__range=[today, limit_date])
        )
        
        expired = []
        expiring_soon = []
        
        for op in queryset:
            data = {
                'id': op.id,
                'nombre': op.nombre,
                'fecha_estimada_cierre': op.fecha_estimada_cierre,
                'empresa_nombre': op.empresa.nombre if op.empresa else "Sin Empresa"
            }
            if op.fecha_estimada_cierre < today:
                expired.append(data)
            else:
                expiring_soon.append(data)
                
        # --- Audit Log for Notifications ---
        try:
            from audit.models import AuditLog
            from django.contrib.contenttypes.models import ContentType
            
            if expired or expiring_soon:
                AuditLog.objects.create(
                    user=user,
                    action='NOTIFICATION',
                    content_type=ContentType.objects.get_for_model(OportunidadDeVenta),
                    description=f"Notifications checked: {len(expired)} expired, {len(expiring_soon)} expiring soon",
                    data_after={
                        'expired_ids': [x['id'] for x in expired], 
                        'expiring_soon_ids': [x['id'] for x in expiring_soon]
                    }
                )
        except Exception as e:
            print(f"Error auditing notifications: {e}")
        # -----------------------------------

        return Response({
            'expired': expired,
            'expiring_soon': expiring_soon,
            'count': len(expired) + len(expiring_soon)
        })


class IncidenciaViewSet(viewsets.ModelViewSet):
    """
    ViewSet para manejar incidencias (usadas como comentarios) de oportunidades.
    """
    from Models.incidencia_model import Incidencia
    queryset = Incidencia.objects.all().order_by('-fecha_creacion')
    serializer_class = IncidenciaSerializer

    def get_queryset(self):
        """
        Permite filtrar por oportunidad_id
        """
        qs = super().get_queryset()
        oportunidad_id = self.request.query_params.get('oportunidad_id')
        if oportunidad_id:
            qs = qs.filter(oportunidad_id=oportunidad_id)
        return qs

    def perform_create(self, serializer):
        user = None
        if self.request.user and self.request.user.is_authenticated:
            # Handle AuthenticatedUserProxy or standard user
            user = getattr(self.request.user, '_user', self.request.user)
            
        serializer.save(usuario=user) 


