import logging
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404
from django.http import HttpResponse
from django.template.loader import render_to_string

from .models import BusinessPlan, Investment, HumanResource, StartupCost, RevenueForecast, ExpenseForecast
from .serializers import BusinessPlanSerializer, InvestmentSerializer
from .services import FinancialEngine
from .utils_pdf import generate_business_plan_pdf
from .utils_template import get_bp_template_context
from market.models import MarketSurvey
from payment.utils import user_has_paid_for_document
from payment.pdf_utils import truncate_pdf_to_preview

logger = logging.getLogger(__name__)


class BusinessPlanViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticated]
    serializer_class = BusinessPlanSerializer

    def get_queryset(self):
        user = self.request.user
        if getattr(user, 'is_staff', False):
            return BusinessPlan.objects.all().order_by('-created_at')
        if getattr(user, 'role', None) == 'MENTOR':
            return BusinessPlan.objects.filter(entrepreneur__mentor=user).order_by('-created_at')
        return BusinessPlan.objects.filter(entrepreneur=user).order_by('-created_at')

    def create(self, request, *args, **kwargs):
        if getattr(request.user, 'role', None) == 'MENTOR':
            raise PermissionDenied("Le mentor ne peut que consulter les Business Plans de ses étudiants.")
        """
        Création ou mise à jour (upsert) : un seul BP par utilisateur (OneToOne).
        Si l'utilisateur a déjà un BP, on met à jour au lieu de créer.
        """
        existing = BusinessPlan.objects.filter(entrepreneur=request.user).first()
        if existing:
            serializer = self.get_serializer(existing, data=request.data, partial=True)
            if not serializer.is_valid():
                logger.warning(
                    "[BP] POST (upsert) validation failed: pk=%s errors=%s | user=%s",
                    existing.pk,
                    serializer.errors,
                    getattr(request.user, "id", None),
                )
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
            try:
                serializer.save()
            except Exception as e:
                logger.exception("[BP] POST (upsert) save error: %s", e)
                raise
            return Response(serializer.data, status=status.HTTP_200_OK)

        serializer = self.get_serializer(data=request.data)
        if not serializer.is_valid():
            logger.warning(
                "[BP] POST validation failed: errors=%s | user=%s",
                serializer.errors,
                getattr(request.user, "id", None),
            )
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        try:
            self.perform_create(serializer)
        except Exception as e:
            logger.exception("[BP] POST perform_create error: %s", e)
            raise
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def update(self, request, *args, **kwargs):
        if getattr(request.user, 'role', None) == 'MENTOR':
            raise PermissionDenied("Le mentor ne peut que consulter les Business Plans de ses étudiants.")
        """Mise à jour avec logs en cas d'erreur de validation."""
        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(
                "[BP] PATCH/PUT validation failed: pk=%s errors=%s | user=%s",
                instance.pk,
                serializer.errors,
                getattr(request.user, "id", None),
            )
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        try:
            self.perform_update(serializer)
        except Exception as e:
            logger.exception("[BP] PATCH/PUT perform_update error: %s", e)
            raise
        return Response(serializer.data)

    def destroy(self, request, *args, **kwargs):
        if getattr(request.user, 'role', None) == 'MENTOR':
            raise PermissionDenied("Le mentor ne peut que consulter les Business Plans de ses étudiants.")
        return super().destroy(request, *args, **kwargs)

    def perform_create(self, serializer):
        # Même seuil que market/views.py (REQUIRED_RESPONSES). Pour 100 : mettre 100.
        REQUIRED_MARKET_RESPONSES = 2
        study = MarketSurvey.objects.filter(entrepreneur=self.request.user).first()
        if not study or study.responses.count() < REQUIRED_MARKET_RESPONSES:
            raise PermissionDenied(
                f"Vous devez avoir au moins {REQUIRED_MARKET_RESPONSES} réponses à l'étude de marché pour créer un Business Plan."
            )
        serializer.save(entrepreneur=self.request.user)

    @action(detail=True, methods=['get'])
    def financial_preview(self, request, pk=None):
        bp = self.get_object()
        engine = FinancialEngine(bp)
        
        global_costs = engine.calculate_global_costs()
        loan_schedule = engine.calculate_loan_schedule(global_costs['loan_amount'])
        amortization = engine.calculate_amortization_table()
        
        pnl_normal = engine.generate_pnl("NORMAL")
        pnl_pessimist_rev = engine.generate_pnl("PESSIMIST_REV")
        pnl_pessimist_cost = engine.generate_pnl("PESSIMIST_COST")

        return Response({
            "global_costs": global_costs,
            "loan_schedule": loan_schedule,
            "amortization": amortization,
            "pnl_normal": pnl_normal,
            "pnl_sensitivity_revenue": pnl_pessimist_rev,
            "pnl_sensitivity_costs": pnl_pessimist_cost
        })

    @action(detail=True, methods=['get'], url_path='document_html')
    def document_html(self, request, pk=None):
        """Retourne le BP en HTML (template joli) avec les données réelles + financières."""
        bp = self.get_object()
        engine = FinancialEngine(bp)
        global_costs = engine.calculate_global_costs()
        loan_schedule = engine.calculate_loan_schedule(global_costs["loan_amount"])
        amortization = engine.calculate_amortization_table()
        pnl_normal = engine.generate_pnl("NORMAL")
        financial_data = {
            "global_costs": global_costs,
            "loan_schedule": loan_schedule,
            "amortization": amortization,
            "pnl_normal": pnl_normal,
        }
        context = get_bp_template_context(bp, financial_data)
        context["show_full_bp"] = user_has_paid_for_document(request.user, "bp")
        html = render_to_string("bp/index.html", context)
        return HttpResponse(html, content_type="text/html; charset=utf-8")

    @action(detail=True, methods=['get'])
    def generate_pdf(self, request, pk=None):
        """Voir (view=1 / format=html) → template HTML ; Télécharger → PDF (aperçu ou complet payant)."""
        bp = 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"))
        is_preview = request.query_params.get("preview") == "1"

        if is_preview:
            # Aperçu gratuit : premières pages uniquement
            engine = FinancialEngine(bp)
            global_costs = engine.calculate_global_costs()
            loan_schedule = engine.calculate_loan_schedule(global_costs['loan_amount'])
            amortization = engine.calculate_amortization_table()
            pnl_normal = engine.generate_pnl("NORMAL")
            pnl_sensitivity_revenue = engine.generate_pnl("PESSIMIST_REV")
            pnl_sensitivity_costs = engine.generate_pnl("PESSIMIST_COST")
            financial_data = {
                "global_costs": global_costs,
                "loan_schedule": loan_schedule,
                "amortization": amortization,
                "pnl_normal": pnl_normal,
                "pnl_sensitivity_revenue": pnl_sensitivity_revenue,
                "pnl_sensitivity_costs": pnl_sensitivity_costs,
            }
            buffer = generate_business_plan_pdf(bp, financial_data)
            pdf_bytes = truncate_pdf_to_preview(buffer.getvalue())
            response = HttpResponse(pdf_bytes, content_type="application/pdf")
            response["Content-Disposition"] = 'inline; filename="BusinessPlan_apercu.pdf"'
            return response

        # Téléchargement complet : réservé aux utilisateurs ayant payé
        if not user_has_paid_for_document(request.user, "bp"):
            return Response(
                {"error": "payment_required", "message": "Débloquez le document pour le télécharger."},
                status=402,
            )

        engine = FinancialEngine(bp)
        global_costs = engine.calculate_global_costs()
        loan_schedule = engine.calculate_loan_schedule(global_costs['loan_amount'])
        amortization = engine.calculate_amortization_table()
        pnl_normal = engine.generate_pnl("NORMAL")
        pnl_sensitivity_revenue = engine.generate_pnl("PESSIMIST_REV")
        pnl_sensitivity_costs = engine.generate_pnl("PESSIMIST_COST")
        financial_data = {
            "global_costs": global_costs,
            "loan_schedule": loan_schedule,
            "amortization": amortization,
            "pnl_normal": pnl_normal,
            "pnl_sensitivity_revenue": pnl_sensitivity_revenue,
            "pnl_sensitivity_costs": pnl_sensitivity_costs,
        }
        buffer = generate_business_plan_pdf(bp, financial_data)
        response = HttpResponse(buffer.getvalue(), content_type="application/pdf")
        response["Content-Disposition"] = f'attachment; filename="BusinessPlan_{bp.company_name[:30].replace(" ", "_")}.pdf"'
        return response