import mimetypes

from django.http import HttpResponse
from django.shortcuts import get_object_or_404

from management.management.utils.utils import create_audit_log
from management.models.review_ticket import ReviewAllegati, ReviewTicket
from management.models.utente import Utente
from management.repositories.review_ticket import ReviewTicketRepository
from management.serializers.review_ticket_serializer import ReviewTicketAllegatiListSerializer, ReviewTicketAttachmentSerializer, ReviewTicketSerializer
from gestionestudio_api import settings
from .base import *
from django.core.exceptions import SuspiciousOperation
from django.utils.encoding import smart_str
from django.contrib.contenttypes.models import ContentType

class ReviewTicketAPIView(GenericViewSet):
    authentication_classes = [TokenAuthentication]
    _repository = ReviewTicketRepository()
    
    @requires_auth(permission=[os.getenv('GESTORE'), os.getenv('INCARICATO')])    
    def get_items(self, request: Request, pk: int) -> Response:
        try:
            review_tickets = ReviewTicket.objects.filter(plan=pk)
            serializer = ReviewTicketSerializer(review_tickets, many=True)
            return Response(serializer.data)
        except Exception as e:
            print("Exception:", e)  # Debug
            handle_exception(e)
            return Response({"error": str(e)}, status=500)
    
    @requires_auth(permission=[os.getenv('GESTORE'), os.getenv('INCARICATO')])
    def save_item(self, request: Request):
        try:
            with transaction.atomic(): # Opzionale: garantisce che se i file falliscono, il ticket viene annullato
                dto = request.data.dict() if hasattr(request.data, 'dict') else dict(request.data)
                dto["redattore"] = request.user_id
                success, errors, review_ticket = self._repository.save(dto, request.user_id)
                
                if not success:
                    raise GenericError({"code": "bad_request", "description": errors}, 400)
        
                response_data = {
                    "status": True,
                    "message": "Review salvata con successo",
                    "device_request_id": review_ticket.id,
                }

                files = request.FILES.getlist('files')
                if files:
                    upload_response = self.upload_review_ticket_attachments(request, review_ticket.id)
                    
                    if upload_response.status_code >= 400:
                         raise GenericError(upload_response.data, upload_response.status_code)

                    response_data["attachments"] = upload_response.data.get("attachments", [])
                    response_data["attachments_message"] = upload_response.data.get("message")
                
                return Response(
                    response_data,
                    status=status.HTTP_201_CREATED if "id" not in dto else status.HTTP_200_OK
                )
        except Exception as e:
            handle_exception(e)

    @requires_auth(permission=[os.getenv('GESTORE'), os.getenv('INCARICATO')])
    def close_review(self, request, review_id):
        try:
            review = ReviewTicket.objects.get(pk=review_id)
            review.risposta = request.data.get('risposta')
            
            if request.data.get('data_chiusura'):
                review.data_chiusura = request.data.get('data_chiusura').split('T')[0]
            
            review.stato = 1 
            
            review.save()
            plan_id = review.plan_id
            old_values = {
                "data_chiusura": None,
                "stato": 0
            }
            new_values = {
                "data_chiusura": review.data_chiusura,
                "stato": 1
            }
            
            create_audit_log(
                user=request.user_id,
                activity_type='CHIUSURA REVISIONE',
                entity_name='ReviewTicket',
                content_type=ContentType.objects.get_for_model(ReviewTicket),
                entity_id=plan_id,
                old_values=old_values,
                new_values=new_values
            )
            return Response({"status": True, "message": "Review chiusa correttamente"})
        except ReviewTicket.DoesNotExist:
            return Response({"error": "Review non trovata"}, status=404)

    @requires_auth(permission=[os.getenv('GESTORE')])
    def upload_review_ticket_attachments(self, request: Request, review_id=None):
        review_id = review_id or request.data.get('review_id')
        files = request.FILES.getlist('files')

        if not review_id:
            return Response({'error': 'review_id è richiesto'}, status=status.HTTP_400_BAD_REQUEST)

        attachments = []
        errors = []
        try:
            for file in files:
                data = {
                    'review': review_id,
                    'file': file,
                    'nome': file.name,
                }

                serializer = ReviewTicketAttachmentSerializer(data=data)
                if serializer.is_valid():
                    attachment = serializer.save()
                    attachments.append(attachment)
                else:
                    errors.append({
                        'file': file.name,
                        'errors': serializer.errors
                    })
            if errors:
                raise Exception("Errori durante il salvataggio")

        except Exception:
            return Response(
                {
                    'error': 'Errore durante il salvataggio dei file',
                    'details': errors
                },
                status=status.HTTP_400_BAD_REQUEST
            )

        result_serializer = ReviewTicketAllegatiListSerializer(attachments, many=True)

        return Response(
            {
                'message': f'{len(attachments)} file salvati con successo',
                'attachments': result_serializer.data
            },
            status=status.HTTP_201_CREATED
        )

    @requires_auth(permission=[os.getenv('GESTORE'), os.getenv('INCARICATO')])
    def download_review_attachment(self, request, review_id=None, attachment_id=None):        
        try:
            # Verifica che l'allegato esista e appartenga al progetto
            attachment = get_object_or_404(
                ReviewAllegati, 
                id=attachment_id, 
                review=review_id
            )
            
            relative_path = attachment.location
            file_path = os.path.join(settings.MEDIA_ROOT, relative_path)
            if not os.path.exists(file_path):
                return Response(
                    {'error': 'Attachment non trovato'},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # Verifica di sicurezza: prevenzione path traversal
            file_path = os.path.abspath(file_path)
            if not self._is_safe_path(file_path):
                raise SuspiciousOperation("Percorso file non sicuro")
            
            # Determina il tipo MIME
            content_type, _ = mimetypes.guess_type(file_path)
            if content_type is None:
                content_type = 'application/octet-stream'
            
            # Legge il file
            try:
                with open(file_path, 'rb') as file:
                    file_content = file.read()
            except IOError:
                return Response(
                    {'error': 'Impossibile leggere il file'},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            response = HttpResponse(file_content, content_type=content_type)
            filename = self._get_safe_filename(attachment.nome or os.path.basename(file_path))
            response['Content-Disposition'] = f'attachment; filename="{smart_str(filename)}"'
            response['Content-Length'] = len(file_content)
            
            # Headers di sicurezza aggiuntivi
            response['X-Content-Type-Options'] = 'nosniff'
            response['X-Frame-Options'] = 'DENY'
            
            return response
            
        except ReviewAllegati.DoesNotExist:
                return Response(
                    {'error': 'Attachment non trovato'},
                    status=status.HTTP_404_NOT_FOUND
                )
        except Exception as e:
            # Log dell'errore per debugging
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Errore nel download dell'allegato {attachment_id}: {str(e)}")
            return Response(
                {'error': 'Errore lettura file'},
                status=status.HTTP_404_NOT_FOUND
            )

    def _is_safe_path(self, file_path):
        SAFE_ROOT = os.path.abspath(os.path.join(settings.MEDIA_ROOT, 'review_allegati'))
        file_path = os.path.normpath(file_path)
        
        return file_path.startswith(SAFE_ROOT)
    
    def _get_safe_filename(self, filename):
        import re
        safe_filename = re.sub(r'[^\w\s.-]', '', filename).strip()
        
        if len(safe_filename) > 255:
            name, ext = os.path.splitext(safe_filename)
            safe_filename = name[:250] + ext
        
        return safe_filename or 'attachment'
        