import logging
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string

from .models import BusinessModelCanvas, PitchDeck, AssistantChatMessage
from .utils_template import get_bmc_template_context
from .assistant_service import get_assistant_reply, suggest_document_template
from .serializers import BMCSerializer, PitchDeckSerializer
from business_plan.models import BusinessPlan
from .utils_pdf import generate_bmc_pdf_file, generate_pitch_pdf_file
from .utils_pptx import generate_pitch_pptx_file
from payment.utils import user_has_paid_for_document
from payment.pdf_utils import truncate_pdf_to_preview

logger = logging.getLogger(__name__)


def _pdf_bytes(buffer):
    return buffer.getvalue() if hasattr(buffer, "getvalue") else buffer

class BMCViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated]
    serializer_class = BMCSerializer

    def get_queryset(self):
        user = self.request.user
        if getattr(user, 'is_staff', False):
            return BusinessModelCanvas.objects.all()
        if getattr(user, 'role', None) == 'MENTOR':
            return BusinessModelCanvas.objects.filter(entrepreneur__mentor=user)
        return BusinessModelCanvas.objects.filter(entrepreneur=user)

    def perform_create(self, serializer):
        # SÉCURITÉ : On vérifie que le Business Plan existe avant de créer le BMC
        if not BusinessPlan.objects.filter(entrepreneur=self.request.user).exists():
            raise permissions.PermissionDenied("Vous devez terminer votre Business Plan avant de faire le BMC.")
        serializer.save(entrepreneur=self.request.user)

    @action(detail=True, methods=['get'], url_path='document_html')
    def document_html(self, request, pk=None):
        """Retourne le BMC en HTML. 3–4 blocs visibles gratuitement, le reste débloqué si payé."""
        bmc = self.get_object()
        context = get_bmc_template_context(bmc, request)
        context["bmc_has_paid"] = user_has_paid_for_document(request.user, "bmc")
        html = render_to_string("bmc/index.html", context)
        return HttpResponse(html, content_type="text/html; charset=utf-8")

    @action(detail=True, methods=['get'])
    def download_pdf(self, request, pk=None):
        """Génère le BMC. format=html / view=1 / preview=1 → template HTML (joli) ; sinon PDF (aperçu ou complet payant)."""
        bmc = self.get_object()
        if (
            request.query_params.get("format") == "html"
            or request.query_params.get("view") == "1"
            or request.query_params.get("preview") == "1"
        ):
            return self.document_html(request, self.kwargs.get("pk"))
        template = (request.query_params.get("template") or "classic").strip().lower()
        if template not in ("classic", "modern", "minimal"):
            template = "classic"
        is_preview = request.query_params.get("preview") == "1"

        if is_preview:
            buffer = generate_bmc_pdf_file(bmc, template=template)
            pdf_bytes = truncate_pdf_to_preview(_pdf_bytes(buffer))
            response = HttpResponse(pdf_bytes, content_type="application/pdf")
            response["Content-Disposition"] = 'inline; filename="BMC_apercu.pdf"'
            return response

        if not user_has_paid_for_document(request.user, "bmc"):
            return Response(
                {"error": "payment_required", "message": "Débloquez le document pour le télécharger."},
                status=402,
            )

        buffer = generate_bmc_pdf_file(bmc, template=template)
        filename = f"BMC_{getattr(request.user, 'last_name', 'canvas')}.pdf"
        disposition = "inline" if request.query_params.get("view") == "1" else "attachment"
        response = HttpResponse(_pdf_bytes(buffer), content_type="application/pdf")
        response["Content-Disposition"] = f'{disposition}; filename="{filename}"'
        return response


class AssistantChatView(APIView):
    """Chat IA contextuel pour les pages Étude de marché, BMC, BP, Pitch. Historique stocké en base."""
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        """Retourne l'historique des messages pour la page donnée (query: ?page=bmc)."""
        page = (request.query_params.get("page") or "").strip().lower()
        if page not in ("market", "bmc", "bp", "pitch"):
            return Response({"detail": "Paramètre page invalide."}, status=status.HTTP_400_BAD_REQUEST)
        qs = AssistantChatMessage.objects.filter(user=request.user, page=page).order_by("created_at")
        messages = [{"role": m.role, "content": m.content, "created_at": m.created_at.isoformat()} for m in qs]
        return Response({"messages": messages})

    def post(self, request):
        page = (request.data.get("page") or "").strip().lower()
        message = (request.data.get("message") or "").strip()
        context = request.data.get("context")
        if not message:
            return Response({"detail": "Le champ 'message' est requis."}, status=status.HTTP_400_BAD_REQUEST)
        if page not in ("market", "bmc", "bp", "pitch"):
            return Response({"detail": "Page invalide. Valeurs attendues : market, bmc, bp, pitch."}, status=status.HTTP_400_BAD_REQUEST)
        if context is not None and not isinstance(context, dict):
            context = {}
        # Sauvegarder le message utilisateur
        AssistantChatMessage.objects.create(user=request.user, page=page, role="user", content=message)
        # Obtenir la réponse IA
        reply = get_assistant_reply(page, message, context or {})
        # Sauvegarder la réponse assistant
        AssistantChatMessage.objects.create(user=request.user, page=page, role="assistant", content=reply)
        return Response({"reply": reply})


class SuggestTemplateView(APIView):
    """Suggère un template PDF (classic | modern | minimal) selon le contexte du projet."""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        page = (request.data.get("page") or "").strip().lower()
        if page not in ("bmc", "pitch"):
            return Response({"detail": "Page invalide. Valeurs : bmc, pitch."}, status=status.HTTP_400_BAD_REQUEST)
        context = request.data.get("context")
        if context is not None and not isinstance(context, dict):
            context = {}
        template = suggest_document_template(page, context or {})
        return Response({"template": template})


class PitchDeckViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated]
    serializer_class = PitchDeckSerializer

    def get_queryset(self):
        user = self.request.user
        if getattr(user, 'is_staff', False):
            return PitchDeck.objects.all()
        if getattr(user, 'role', None) == 'MENTOR':
            return PitchDeck.objects.filter(entrepreneur__mentor=user)
        return PitchDeck.objects.filter(entrepreneur=user)

    def create(self, request, *args, **kwargs):
        if getattr(request.user, 'role', None) == 'MENTOR':
            return Response(
                {"detail": "Le mentor ne peut que consulter les Pitch Decks de ses étudiants."},
                status=status.HTTP_403_FORBIDDEN,
            )
        if not BusinessModelCanvas.objects.filter(entrepreneur=request.user).exists():
            return Response(
                {"detail": "Vous devez terminer votre BMC avant de faire le Pitch Deck."},
                status=status.HTTP_403_FORBIDDEN,
            )
        serializer = self.get_serializer(data=request.data)
        if not serializer.is_valid():
            logger.warning("[Pitch] POST validation failed: errors=%s | user=%s", serializer.errors, request.user.id)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def update(self, request, *args, **kwargs):
        if getattr(request.user, 'role', None) == 'MENTOR':
            return Response(
                {"detail": "Le mentor ne peut que consulter les Pitch Decks de ses étudiants."},
                status=status.HTTP_403_FORBIDDEN,
            )
        partial = kwargs.pop("partial", False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        if not serializer.is_valid():
            logger.warning("[Pitch] PATCH validation failed: errors=%s | user=%s", serializer.errors, request.user.id)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        self.perform_update(serializer)
        return Response(serializer.data)

    def destroy(self, request, *args, **kwargs):
        if getattr(request.user, 'role', None) == 'MENTOR':
            return Response(
                {"detail": "Le mentor ne peut que consulter les Pitch Decks de ses étudiants."},
                status=status.HTTP_403_FORBIDDEN,
            )
        return super().destroy(request, *args, **kwargs)

    def perform_create(self, serializer):
        serializer.save(entrepreneur=self.request.user)

    @action(detail=True, methods=['get'])
    def download_pdf(self, request, pk=None):
        """Génère le PDF du Pitch. preview=1 → aperçu. Sinon réservé aux payants."""
        pitch = self.get_object()
        template = (request.query_params.get("template") or "classic").strip().lower()
        if template not in ("classic", "modern", "minimal"):
            template = "classic"
        is_preview = request.query_params.get("preview") == "1"

        if is_preview:
            try:
                buffer = generate_pitch_pdf_file(pitch, template=template)
            except Exception as e:
                logger.exception("[Pitch] PDF generation failed: %s", e)
                return Response(
                    {"detail": "Erreur lors de la génération du PDF."},
                    status=status.HTTP_500_INTERNAL_SERVER_ERROR,
                )
            pdf_bytes = truncate_pdf_to_preview(_pdf_bytes(buffer))
            response = HttpResponse(pdf_bytes, content_type="application/pdf")
            response["Content-Disposition"] = 'inline; filename="Pitch_apercu.pdf"'
            return response

        if not user_has_paid_for_document(request.user, "pitch"):
            return Response(
                {"error": "payment_required", "message": "Débloquez le document pour le télécharger."},
                status=402,
            )

        try:
            buffer = generate_pitch_pdf_file(pitch, template=template)
        except Exception as e:
            logger.exception("[Pitch] PDF generation failed: %s", e)
            return Response(
                {"detail": "Erreur lors de la génération du PDF."},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
        filename = f"Pitch_{getattr(request.user, 'last_name', 'deck')}.pdf"
        disposition = "inline" if request.query_params.get("view") == "1" else "attachment"
        response = HttpResponse(_pdf_bytes(buffer), content_type="application/pdf")
        response["Content-Disposition"] = f'{disposition}; filename="{filename}"'
        return response

    @action(detail=True, methods=['get'])
    def download_pptx(self, request, pk=None):
        """Génère le PowerPoint du Pitch (.pptx). Réservé aux payants."""
        pitch = self.get_object()
        if not user_has_paid_for_document(request.user, "pitch"):
            return Response(
                {"error": "payment_required", "message": "Débloquez le document pour le télécharger."},
                status=402,
            )
        try:
            buffer = generate_pitch_pptx_file(pitch)
        except Exception as e:
            logger.exception("[Pitch] PPTX generation failed: %s", e)
            return Response(
                {"detail": "Erreur lors de la génération du PowerPoint."},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )
        filename = f"Pitch_{getattr(request.user, 'last_name', 'deck')}.pptx"
        response = HttpResponse(buffer.getvalue(), content_type="application/vnd.openxmlformats-officedocument.presentationml.presentation")
        response["Content-Disposition"] = f'attachment; filename="{filename}"'
        return response