from asyncio import sleep
import locale
import os
import re
from tempfile import NamedTemporaryFile
from decimal import Decimal
from django.utils.dateparse import parse_date
from django.shortcuts import (
    render,
    HttpResponse,
    get_object_or_404,
    redirect,
    get_list_or_404,
)
from django.template.loader import render_to_string
from django.db.models import Count
from django.db import models
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.utils import timezone
import json
from .notifications import send_project_notifications, send_activity_notifications
from django.core.paginator import Paginator
import datetime
from collections import Counter, defaultdict
import calendar
from django.db import transaction
from django.http import JsonResponse
from django.urls import reverse
import uuid
from django.urls import reverse
import qrcode
import requests
from django.views.decorators.csrf import csrf_exempt
from django.core.mail import send_mail
from django.conf import settings

# import csrf_exempt


from django.db.models import Q
from projects import settings
from userapp.models import USER_TYPE, CostumUser, User
from django.utils.encoding import force_str, force_bytes
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.core.mail import send_mail
from django.template.loader import render_to_string

from xhtml2pdf import pisa
from userapp.token import account_activation_token
from userapp.views import send_my_mail
from .models import Customer, Simulation, BlogPost, BlogCategory, Project, ProjectCategory, ProjectImage, ProjectVideo, DashboardProject, ProjectActivity, ActivityImage, ActivityVideo, ActivityFile, Testimonial
from .models import Product, ProductCategory


def is_ajax(request):
    return request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest"


# from django.urls import reverse as urlreverse
# Create your views here.


# utils ::::::::::::::::::::::::::::::::::::::::::::::
# ::::::::::::::::::::::::::::::::::::::::::::::::::::
def is_ajax(request):
    return request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest"


def test(request):
    data = {}
    
    return render(request, "utils/emp_bia.html", data)



# @login_required(login_url="/auth/to_login")
def simulation(request):

    return render(request, "simulation.html", {})


# ========================================
# VUES POUR GESTION DES SIMULATIONS
# ========================================

def get_client_ip(request):
    """Récupère l'adresse IP du client"""
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0]
    else:
        ip = request.META.get('REMOTE_ADDR')
    return ip

@csrf_exempt
def save_simulation(request):
    """
    Vue pour enregistrer une nouvelle simulation ou mettre à jour une existante
    """
    if request.method != 'POST':
        return JsonResponse({'error': 'Méthode non autorisée'}, status=405)
    
    try:
        # Récupérer les données JSON
        data = json.loads(request.body)
        
        # Validation des données obligatoires
        required_fields = ['email', 'full_name', 'phone', 'project_type', 'standing', 
                          'niveau', 'region', 'surface_terrain', 'surface_batie', 
                          'cout_gros_oeuvre', 'cout_second_oeuvre', 'cout_total', 'prix_m2']
        
        for field in required_fields:
            if field not in data or not data[field]:
                return JsonResponse({'error': f'Champ manquant: {field}'}, status=400)
        
        # Créer ou récupérer le client
        customer, created = Customer.objects.get_or_create(
            email=data['email'],
            defaults={
                'full_name': data['full_name'],
                'phone': data.get('phone', ''),
            }
        )
        
        # Si le client existe déjà, mettre à jour ses informations
        if not created:
            customer.full_name = data['full_name']
            customer.phone = data.get('phone', customer.phone)
            customer.save()
        
        # Vérifier s'il faut mettre à jour une simulation existante
        existing_simulation_id = data.get('existing_simulation_id')
        simulation = None
        
        if existing_simulation_id:
            try:
                simulation = Simulation.objects.get(
                    id=existing_simulation_id, 
                    customer=customer
                )
                # Mettre à jour la simulation existante
                simulation.project_type = data['project_type']
                simulation.standing = data['standing']
                simulation.niveau = data['niveau']
                simulation.region = data['region']
                simulation.surface_terrain = int(data['surface_terrain'])
                simulation.surface_batie = int(data['surface_batie'])
                simulation.ascenseur = data.get('ascenseur', False)
                simulation.fondation_choice = data.get('fondation_choice', 'Auto')
                simulation.options_sans_prix = data.get('options_sans_prix', [])
                simulation.cout_gros_oeuvre = int(data['cout_gros_oeuvre'])
                simulation.cout_second_oeuvre = int(data['cout_second_oeuvre'])
                simulation.cout_ascenseur = int(data.get('cout_ascenseur', 0))
                simulation.cout_total = int(data['cout_total'])
                simulation.prix_m2 = int(data['prix_m2'])
                
                # Mettre à jour les informations de devis si c'est une demande de devis
                if data.get('quote_requested'):
                    simulation.localisation_projet = data.get('localisation_projet', '')
                    simulation.a_terrain = data.get('a_terrain')
                    simulation.adresse_terrain = data.get('adresse_terrain', '')
                    simulation.conseil_terrain = data.get('conseil_terrain', False)
                    simulation.projet_actuel = data.get('projet_actuel')
                    simulation.delai_projet = data.get('delai_projet', '')
                    simulation.a_plan = data.get('a_plan')
                    simulation.message_client = data.get('message_client', '')
                    simulation.status = 'QUOTE_REQUESTED'
                
                simulation.save()
                print(f"✅ Simulation {simulation.id} mise à jour")
                
            except Simulation.DoesNotExist:
                # Si la simulation n'existe pas, en créer une nouvelle
                simulation = None
        
        # Créer une nouvelle simulation si aucune mise à jour n'a eu lieu
        if simulation is None:
            simulation = Simulation.objects.create(
                customer=customer,
                project_type=data['project_type'],
                standing=data['standing'],
                niveau=data['niveau'],
                region=data['region'],
                surface_terrain=int(data['surface_terrain']),
                surface_batie=int(data['surface_batie']),
                ascenseur=data.get('ascenseur', False),
                fondation_choice=data.get('fondation_choice', 'Auto'),
                options_sans_prix=data.get('options_sans_prix', []),
                cout_gros_oeuvre=int(data['cout_gros_oeuvre']),
                cout_second_oeuvre=int(data['cout_second_oeuvre']),
                cout_ascenseur=int(data.get('cout_ascenseur', 0)),
                cout_total=int(data['cout_total']),
                prix_m2=int(data['prix_m2']),
                
                # Informations complémentaires pour le devis
                localisation_projet=data.get('localisation_projet', ''),
                a_terrain=data.get('a_terrain'),
                adresse_terrain=data.get('adresse_terrain', ''),
                conseil_terrain=data.get('conseil_terrain', False),
                projet_actuel=data.get('projet_actuel'),
                delai_projet=data.get('delai_projet', ''),
                a_plan=data.get('a_plan'),
                message_client=data.get('message_client', ''),
                
                # Tracking
                ip_address=get_client_ip(request),
                user_agent=request.META.get('HTTP_USER_AGENT', ''),
                status='QUOTE_REQUESTED' if data.get('quote_requested') else 'COMPLETED'
            )
            print(f"✅ Nouvelle simulation {simulation.id} créée")
        
        # Envoyer notification à l'entreprise si c'est une demande de devis
        if data.get('quote_requested'):
            send_quote_notification(simulation)
        
        return JsonResponse({
            'success': True,
            'simulation_id': simulation.id,
            'customer_id': customer.id,
            'message': 'Simulation enregistrée avec succès' if simulation else 'Simulation mise à jour avec succès'
        })
        
    except json.JSONDecodeError:
        return JsonResponse({'error': 'Format JSON invalide'}, status=400)
    except Exception as e:
        return JsonResponse({'error': f'Erreur serveur: {str(e)}'}, status=500)


def send_quote_notification(simulation):
    """
    Envoie une notification email à l'entreprise pour une nouvelle demande de devis
    """
    try:
        subject = f"🏗️ Nouvelle demande de devis ECOLUX - {simulation.customer.full_name}"
        
        # Formater les options sans prix
        options_text = ""
        if simulation.options_sans_prix:
            options_text = f"\nOptions demandées : {', '.join(simulation.options_sans_prix)}"
        
        message = f"""
Nouvelle demande de devis reçue via l'estimateur ECOLUX !

📋 INFORMATIONS CLIENT
- Nom : {simulation.customer.full_name}
- Email : {simulation.customer.email}
- Téléphone : {simulation.customer.phone}
- Localisation : {simulation.localisation_projet or 'Non spécifiée'}

🏗️ DÉTAILS DU PROJET
- Type : {simulation.project_type}
- Standing : {simulation.standing}
- Hauteur : {simulation.niveau}
- Région : {simulation.region}
- Surface terrain : {simulation.surface_terrain} m²
- Surface bâtie : {simulation.surface_batie} m²
- Ascenseur : {'Oui' if simulation.ascenseur else 'Non'}
- Fondation : {simulation.fondation_choice}{options_text}

💰 ESTIMATION
- Gros Œuvre : {simulation.cout_gros_oeuvre:,} FCFA
- Second Œuvre : {simulation.cout_second_oeuvre:,} FCFA
- Ascenseur : {simulation.cout_ascenseur:,} FCFA
- TOTAL : {simulation.cout_total:,} FCFA
- Prix au m² : {simulation.prix_m2:,} FCFA/m²

📝 INFORMATIONS COMPLÉMENTAIRES
- Possède un terrain : {'Oui' if simulation.a_terrain else 'Non' if simulation.a_terrain is not None else 'Non spécifié'}
- Adresse terrain : {simulation.adresse_terrain or 'Non spécifiée'}
- Conseil terrain : {'Oui' if simulation.conseil_terrain else 'Non'}
- Projet actuel : {'Oui' if simulation.projet_actuel else 'Non' if simulation.projet_actuel is not None else 'Non spécifié'}
- Délai souhaité : {simulation.delai_projet or 'Non spécifié'}
- Possède un plan : {'Oui' if simulation.a_plan else 'Non' if simulation.a_plan is not None else 'Non spécifié'}

💬 MESSAGE DU CLIENT
{simulation.message_client or 'Aucun message'}

🔗 ACTIONS
- Répondre directement à {simulation.customer.email}
- Appeler le {simulation.customer.phone}

---
Simulation #{simulation.id} créée le {simulation.created_at.strftime('%d/%m/%Y à %H:%M')}
"""
        
        # Email de l'entreprise (à configurer dans settings)
        recipient_email = getattr(settings, 'ECOLUX_NOTIFICATION_EMAIL', 'contact.ecolux@gmail.com')
        # recipient_email = getattr(settings, 'ECOLUX_NOTIFICATION_EMAIL', 'dessdie43@gmail.com')
        
        send_mail(
            subject=subject,
            message=message,
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[recipient_email],
            fail_silently=False,
        )
        
        return True
        
    except Exception as e:
        print(f"Erreur envoi notification: {e}")
        return False


@login_required(login_url="/auth/to_login")
def simulation_list(request):
    """
    Vue pour lister toutes les simulations (admin)
    """
    simulations = Simulation.objects.select_related('customer').order_by('-created_at')
    
    # Filtres
    status_filter = request.GET.get('status')
    if status_filter:
        simulations = simulations.filter(status=status_filter)
    
    search = request.GET.get('search')
    if search:
        simulations = simulations.filter(
            Q(customer__full_name__icontains=search) |
            Q(customer__email__icontains=search) |
            Q(project_type__icontains=search)
        )
    
    # Pagination
    paginator = Paginator(simulations, 20)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'simulations': page_obj,
        'status_choices': Simulation.STATUS_CHOICES,
        'current_status': status_filter,
        'search_query': search,
    }
    
    return render(request, 'backoffice/simulation_list.html', context)


@login_required(login_url="/auth/to_login")
def simulation_detail(request, simulation_id):
    """
    Vue pour voir le détail d'une simulation
    """
    simulation = get_object_or_404(Simulation, id=simulation_id)
    
    context = {
        'simulation': simulation,
    }
    
    return render(request, 'backoffice/simulation_detail.html', context)


@login_required(login_url="/auth/to_login")
def customer_list(request):
    """
    Vue pour lister tous les clients
    """
    customers = Customer.objects.annotate(
        simulation_count_annotated=Count('simulations')
    ).order_by('-last_simulation_date')
    
    # Recherche
    search = request.GET.get('search')
    if search:
        customers = customers.filter(
            Q(full_name__icontains=search) |
            Q(email__icontains=search)
        )
    
    # Pagination
    paginator = Paginator(customers, 20)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'customers': page_obj,
        'search_query': search,
    }
    
    return render(request, 'backoffice/customer_list.html', context)


@csrf_exempt
def generate_pdf_estimation(request, simulation_id):
    """
    Génère un PDF personnalisé pour une estimation donnée
    """
    try:
        # Récupérer la simulation
        simulation = get_object_or_404(Simulation, id=simulation_id)
        
        # Formatter les valeurs monétaires
        def format_currency(value):
            if value is None or value == 0:
                return "0"
            return f"{int(value):,}".replace(',', ' ')
        
        # Préparer les données formatées
        cout_gros_oeuvre_formatted = format_currency(simulation.cout_gros_oeuvre)
        cout_second_oeuvre_formatted = format_currency(simulation.cout_second_oeuvre)
        cout_ascenseur_formatted = format_currency(simulation.cout_ascenseur) if simulation.cout_ascenseur else "0"
        cout_total_formatted = format_currency(simulation.cout_total)
        prix_m2_formatted = format_currency(simulation.prix_m2) if simulation.prix_m2 else "0"
        
        # Préparer le contexte pour le template
        context = {
            'simulation': simulation,
            'today': timezone.now(),
            # Valeurs formatées
            'cout_gros_oeuvre_formatted': cout_gros_oeuvre_formatted,
            'cout_second_oeuvre_formatted': cout_second_oeuvre_formatted,
            'cout_ascenseur_formatted': cout_ascenseur_formatted,
            'cout_total_formatted': cout_total_formatted,
            'prix_m2_formatted': prix_m2_formatted,
        }
        
        # Rendre le template HTML
        html_string = render_to_string('pdf/estimation_pdf.html', context)
        
        # Créer la réponse HTTP pour affichage dans le navigateur
        response = HttpResponse(content_type='application/pdf')
        response['Content-Disposition'] = f'inline; filename="Estimation_ECOLUX_{simulation.customer.full_name}_{simulation.id}.pdf"'
        
        # Générer le PDF
        pisa_status = pisa.CreatePDF(html_string, dest=response)
        
        if pisa_status.err:
            return HttpResponse('Erreur lors de la génération du PDF', status=500)
            
        return response
        
    except Exception as e:
        return HttpResponse(f'Erreur: {str(e)}', status=500)


@csrf_exempt 
def generate_pdf_quote(request, simulation_id):
    """
    Génère un PDF de devis détaillé personnalisé
    """
    try:
        simulation = get_object_or_404(Simulation, id=simulation_id)
        
        # Vérifier que c'est bien une demande de devis
        if simulation.status != 'QUOTE_REQUESTED':
            return HttpResponse('Cette simulation ne contient pas de demande de devis', status=400)
        
        context = {
            'simulation': simulation,
            'today': timezone.now(),
            'is_quote': True,  # Pour différencier du simple PDF d'estimation
        }
        
        html_string = render_to_string('pdf/devis_pdf.html', context)
        
        response = HttpResponse(content_type='application/pdf')
        response['Content-Disposition'] = f'attachment; filename="Devis_ECOLUX_{simulation.customer.full_name}_{simulation.id}.pdf"'
        
        pisa_status = pisa.CreatePDF(html_string, dest=response)
        
        if pisa_status.err:
            return HttpResponse('Erreur lors de la génération du PDF de devis', status=500)
            
        return response
        
    except Exception as e:
        return HttpResponse(f'Erreur: {str(e)}', status=500)


def get_simulation_details(request, simulation_id):
    """
    API pour récupérer les détails d'une simulation
    """
    try:
        simulation = get_object_or_404(Simulation, id=simulation_id)
        
        data = {
            'id': simulation.id,
            'customer': {
                'full_name': simulation.customer.full_name,
                'email': simulation.customer.email,
                'phone': simulation.customer.phone,
            },
            'project_details': {
                'project_type': simulation.project_type,
                'standing': simulation.standing,
                'niveau': simulation.niveau,
                'region': simulation.region,
                'surface_terrain': simulation.surface_terrain,
                'surface_batie': simulation.surface_batie,
                'ascenseur': simulation.ascenseur,
                'fondation_choice': simulation.fondation_choice,
            },
            'costs': {
                'cout_gros_oeuvre': simulation.cout_gros_oeuvre,
                'cout_second_oeuvre': simulation.cout_second_oeuvre,
                'cout_ascenseur': simulation.cout_ascenseur,
                'cout_total': simulation.cout_total,
                'prix_m2': simulation.prix_m2,
            },
            'options_sans_prix': simulation.options_sans_prix,
            'created_at': simulation.created_at.isoformat(),
            'status': simulation.status,
        }
        
        return JsonResponse({'success': True, 'simulation': data})
        
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)}, status=500)


# ========================================
# VUES POUR LA NOUVELLE PAGE PRINCIPALE
# ========================================

def home(request):
    """
    Page d'accueil dynamique avec contenu du blog et réalisations
    """
    # Récupérer les articles de blog récents (3 derniers publiés)
    recent_posts = BlogPost.objects.filter(
        status='PUBLISHED'
    ).select_related('category', 'author').order_by('-published_at')[:3]
    
    # Récupérer les projets en vedette (6 derniers)
    featured_projects = Project.objects.filter(
        published=True,
        featured=True
    ).select_related('category')[:6]
    
    # Si pas assez de projets en vedette, compléter avec les projets récents
    if featured_projects.count() < 6:
        recent_projects = Project.objects.filter(
            published=True
        ).exclude(
            id__in=[p.id for p in featured_projects]
        ).select_related('category')[:6-featured_projects.count()]
        
        featured_projects = list(featured_projects) + list(recent_projects)
    
    # Récupérer les témoignages actifs
    testimonials = Testimonial.objects.filter(is_active=True).order_by('order', '-created_at')[:6]
    
    # Statistiques pour le hero
    stats = {
        'total_projects': Project.objects.filter(published=True).count(),
        'total_posts': BlogPost.objects.filter(status='PUBLISHED').count(),
        'years_experience': 30,
        'satisfaction_rate': 98,
    }
    
    context = {
        'recent_posts': recent_posts,
        'featured_projects': featured_projects,
        'testimonials': testimonials,
        'stats': stats,
    }
    
    return render(request, 'eco.html', context)


def about(request):
    """
    Page À Propos d'ECOLUX BTP
    """
    context = {
        'page_title': 'À Propos',
    }
    
    return render(request, 'about.html', context)


def packs(request):
    """
    Page Nos Packs / Offres ECOLUX BTP 2025
    """
    context = {
        'page_title': 'Nos Packs',
    }
    return render(request, 'packs.html', context)


def shop(request):
    """Page boutique: liste produits + catégories + recherche"""
    categories = ProductCategory.objects.filter(is_active=True).order_by('order')
    products = Product.objects.filter(status='ACTIVE').select_related('category')

    # Filtre catégorie
    category_slug = request.GET.get('categorie')
    current_category = None
    if category_slug:
        current_category = ProductCategory.objects.filter(slug=category_slug, is_active=True).first()
        if current_category:
            products = products.filter(category=current_category)

    # Recherche
    q = request.GET.get('q')
    if q:
        products = products.filter(models.Q(name__icontains=q) | models.Q(short_description__icontains=q))

    # Mise en avant
    featured = products.filter(is_featured=True)[:6]

    context = {
        'categories': categories,
        'products': products[:50],  # limite initiale
        'featured_products': featured,
        'current_category': current_category,
        'search_query': q or '',
        'whatsapp_number': getattr(settings, 'ECOLUX_WHATSAPP_NUMBER', '221779962626'),
    }
    return render(request, 'shop.html', context)


def product_detail(request, slug):
    """Fiche produit avec lien WhatsApp"""
    product = get_object_or_404(Product, slug=slug, status='ACTIVE')
    whatsapp_number = getattr(settings, 'ECOLUX_WHATSAPP_WHATSAPP_NUMBER', getattr(settings, 'ECOLUX_WHATSAPP_NUMBER', '221770000000'))
    message = product.whatsapp_message
    whatsapp_link = f"https://wa.me/{whatsapp_number}?text={message}"
    related = Product.objects.filter(category=product.category, status='ACTIVE').exclude(id=product.id)[:6]
    context = {
        'product': product,
        'whatsapp_link': whatsapp_link,
        'related_products': related,
    }
    return render(request, 'product_detail.html', context)


# ========================================
# VUES POUR LE BLOG
# ========================================

def blog_list(request):
    """
    Liste des articles de blog avec pagination et filtres
    """
    posts = BlogPost.objects.filter(
        status='PUBLISHED'
    ).select_related('category', 'author').order_by('-published_at')
    
    # Filtre par catégorie
    category_slug = request.GET.get('category')
    selected_category = None
    if category_slug:
        try:
            selected_category = BlogCategory.objects.get(slug=category_slug)
            posts = posts.filter(category=selected_category)
        except BlogCategory.DoesNotExist:
            pass
    
    # Recherche
    search_query = request.GET.get('search')
    if search_query:
        posts = posts.filter(
            Q(title__icontains=search_query) |
            Q(excerpt__icontains=search_query) |
            Q(tags__icontains=search_query)
        )
    
    # Pagination
    paginator = Paginator(posts, 9)  # 9 articles par page
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    # Catégories pour le menu de filtres
    categories = BlogCategory.objects.all()
    
    # Articles en vedette pour la sidebar
    featured_posts = BlogPost.objects.filter(
        status='PUBLISHED',
        featured=True
    ).exclude(
        id__in=[post.id for post in page_obj]
    )[:3]
    
    context = {
        'posts': page_obj,
        'categories': categories,
        'selected_category': selected_category,
        'search_query': search_query,
        'featured_posts': featured_posts,
    }
    
    # Breadcrumb
    breadcrumb_items = [
        {'title': 'Blog', 'url': None}
    ]
    if selected_category:
        breadcrumb_items.append({'title': selected_category.name, 'url': None})
    
    context.update({
        'current_category': selected_category,
        'breadcrumb_items': breadcrumb_items,
    })
    
    return render(request, 'blog_list.html', context)


def blog_detail(request, slug):
    """
    Détail d'un article de blog
    """
    post = get_object_or_404(
        BlogPost.objects.select_related('category', 'author'),
        slug=slug,
        status='PUBLISHED'
    )
    
    # Incrémenter le compteur de vues
    post.increment_views()
    
    # Articles similaires (même catégorie)
    related_posts = BlogPost.objects.filter(
        status='PUBLISHED',
        category=post.category
    ).exclude(id=post.id)[:3]
    
    # Si pas assez d'articles similaires, prendre des articles récents
    if related_posts.count() < 3:
        additional_posts = BlogPost.objects.filter(
            status='PUBLISHED'
        ).exclude(
            id__in=[post.id] + [p.id for p in related_posts]
        )[:3-related_posts.count()]
        
        related_posts = list(related_posts) + list(additional_posts)
    
    # Articles récents pour la sidebar
    recent_posts = BlogPost.objects.filter(
        status='PUBLISHED'
    ).exclude(id=post.id).order_by('-created_at')[:5]
    
    # Catégories avec comptage des articles
    categories = BlogCategory.objects.all()
    for category in categories:
        category.posts_count = BlogPost.objects.filter(
            status='PUBLISHED', 
            category=category
        ).count()
    
    # Breadcrumb
    breadcrumb_items = [
        {'title': 'Blog', 'url': reverse('app:blog_list')},
        {'title': post.title, 'url': None}
    ]
    
    context = {
        'post': post,
        'related_posts': related_posts,
        'recent_posts': recent_posts,
        'categories': categories,
        'breadcrumb_items': breadcrumb_items,
    }
    
    return render(request, 'blog_detail.html', context)


def blog_category(request, slug):
    """
    Articles d'une catégorie spécifique
    """
    category = get_object_or_404(BlogCategory, slug=slug)
    
    posts = BlogPost.objects.filter(
        status='PUBLISHED',
        category=category
    ).select_related('author').order_by('-published_at')
    
    # Pagination
    paginator = Paginator(posts, 9)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'category': category,
        'posts': page_obj,
    }
    
    return render(request, 'blog/blog_category.html', context)


# ========================================
# VUES POUR LES RÉALISATIONS/PROJETS
# ========================================

def projects_list(request):
    """
    Liste des projets/réalisations avec filtres
    """
    # Debug: récupérer tous les projets d'abord
    all_projects = Project.objects.all()
    published_projects = Project.objects.filter(published=True)
    
    projects = Project.objects.filter(
        published=True
    ).select_related('category').prefetch_related('images').order_by('-completed_date', '-created_at')
    
    # Filtre par catégorie
    category_slug = request.GET.get('category')
    selected_category = None
    if category_slug:
        try:
            selected_category = ProjectCategory.objects.get(slug=category_slug)
            projects = projects.filter(category=selected_category)
        except ProjectCategory.DoesNotExist:
            pass
    
    # Filtre par statut
    status_filter = request.GET.get('status')
    if status_filter:
        projects = projects.filter(status=status_filter)
    
    # Recherche
    search_query = request.GET.get('search')
    if search_query:
        projects = projects.filter(
            Q(title__icontains=search_query) |
            Q(location__icontains=search_query) |
            Q(description__icontains=search_query)
        )
    
    # Pagination
    paginator = Paginator(projects, 12)  # 12 projets par page
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    # Catégories pour les filtres
    categories = ProjectCategory.objects.all()
    
    context = {
        'projects': page_obj,
        'categories': categories,
        'selected_category': selected_category,
        'status_filter': status_filter,
        'status_choices': Project.STATUS_CHOICES,
        'search_query': search_query,
        # Debug info
        'debug_total_projects': all_projects.count(),
        'debug_published_projects': published_projects.count(),
    }
    
    # Breadcrumb
    breadcrumb_items = [
        {'title': 'Réalisations', 'url': None}
    ]
    if selected_category:
        breadcrumb_items.append({'title': selected_category.name, 'url': None})
    
    # Statistiques pour la page
    total_projects = Project.objects.filter(published=True).count()
    
    context.update({
        'current_category': selected_category,
        'breadcrumb_items': breadcrumb_items,
        'total_projects': total_projects,
    })
    
    return render(request, 'projects_list.html', context)


def project_detail(request, slug):
    """
    Détail d'un projet/réalisation
    """
    project = get_object_or_404(
        Project.objects.select_related('category'),
        slug=slug,
        published=True
    )
    
    # Incrémenter le compteur de vues
    project.increment_views()
    
    # Images du projet
    project_images = project.images.all().order_by('order')
    
    # Vidéos du projet
    project_videos = project.videos.all().order_by('order')
    
    # Projets similaires (même catégorie)
    related_projects = Project.objects.filter(
        published=True,
        category=project.category
    ).exclude(id=project.id)[:4]
    
    # Si pas assez de projets similaires, prendre des projets récents
    if related_projects.count() < 4:
        additional_projects = Project.objects.filter(
            published=True
        ).exclude(
            id__in=[project.id] + [p.id for p in related_projects]
        )[:4-related_projects.count()]
        
        related_projects = list(related_projects) + list(additional_projects)
    
    context = {
        'project': project,
        'project_images': project_images,
        'project_videos': project_videos,
        'related_projects': related_projects,
    }
    
    return render(request, 'projects/project_detail.html', context)


def project_category(request, slug):
    """
    Projets d'une catégorie spécifique
    """
    category = get_object_or_404(ProjectCategory, slug=slug)
    
    projects = Project.objects.filter(
        published=True,
        category=category
    ).order_by('-completed_date', '-created_at')
    
    # Pagination
    paginator = Paginator(projects, 12)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'category': category,
        'projects': page_obj,
    }
    
    return render(request, 'projects/project_category.html', context)


# ========================================
# VUES AJAX POUR DYNAMISER L'INTERFACE
# ========================================

def load_more_posts(request):
    """
    Charge plus d'articles via AJAX
    """
    page = request.GET.get('page', 1)
    category_slug = request.GET.get('category')
    
    posts = BlogPost.objects.filter(
        status='PUBLISHED'
    ).select_related('category', 'author').order_by('-published_at')
    
    if category_slug:
        try:
            category = BlogCategory.objects.get(slug=category_slug)
            posts = posts.filter(category=category)
        except BlogCategory.DoesNotExist:
            pass
    
    paginator = Paginator(posts, 6)
    page_obj = paginator.get_page(page)
    
    posts_data = []
    for post in page_obj:
        posts_data.append({
            'id': post.id,
            'title': post.title,
            'slug': post.slug,
            'excerpt': post.excerpt,
            'category': post.category.name if post.category else '',
            'category_color': post.category.color if post.category else '#3B82F6',
            'author': post.author.first_name + ' ' + post.author.last_name,
            'published_at': post.published_at.strftime('%d %B %Y') if post.published_at else '',
            'reading_time': post.reading_time,
            'featured_image': post.featured_image.url if post.featured_image else '',
            'url': post.get_absolute_url(),
        })
    
    return JsonResponse({
        'posts': posts_data,
        'has_next': page_obj.has_next(),
        'next_page': page_obj.next_page_number() if page_obj.has_next() else None,
    })


def load_more_projects(request):
    """
    Charge plus de projets via AJAX
    """
    page = request.GET.get('page', 1)
    category_slug = request.GET.get('category')
    
    projects = Project.objects.filter(
        published=True
    ).select_related('category').order_by('-completed_date', '-created_at')
    
    if category_slug:
        try:
            category = ProjectCategory.objects.get(slug=category_slug)
            projects = projects.filter(category=category)
        except ProjectCategory.DoesNotExist:
            pass
    
    paginator = Paginator(projects, 6)
    page_obj = paginator.get_page(page)
    
    projects_data = []
    for project in page_obj:
        projects_data.append({
            'id': project.id,
            'title': project.title,
            'slug': project.slug,
            'short_description': project.short_description,
            'location': project.location,
            'category': project.category.name if project.category else '',
            'surface_built': project.surface_built,
            'completed_date': project.completed_date.strftime('%Y') if project.completed_date else '',
            'main_image': project.main_image.url if project.main_image else '',
            'url': project.get_absolute_url(),
            'status': project.get_status_display(),
        })
    
    return JsonResponse({
        'projects': projects_data,
        'has_next': page_obj.has_next(),
        'next_page': page_obj.next_page_number() if page_obj.has_next() else None,
    })


# ================================
# VUES POUR DASHBOARD INTERNE
# ================================

@login_required(login_url="/auth/to_login")
def dashboard_home(request):
    """Tableau de bord principal selon le type d'utilisateur"""
    user_type = request.user.cuser.type
    
    context = {
        'user_type': user_type,
        'page_title': 'Tableau de bord',
    }
    
    if user_type == 'DRH':
        # DRH voit tout
        context.update({
            'total_projects': DashboardProject.objects.count(),
            'active_projects': DashboardProject.objects.filter(status='IN_PROGRESS').count(),
            'total_activities': ProjectActivity.objects.count(),
            'pending_activities': ProjectActivity.objects.filter(is_completed=False).count(),
            'recent_projects': DashboardProject.objects.order_by('-created_at')[:5],
            'recent_activities': ProjectActivity.objects.select_related('project', 'created_by__user').prefetch_related('assigned_users__user').order_by('-created_at')[:10],
        })
    elif user_type == 'CLIENT':
        # Client voit ses projets
        user_projects = DashboardProject.objects.filter(client=request.user.cuser)
        context.update({
            'my_projects': user_projects,
            'my_projects_count': user_projects.count(),
            'my_active_projects': user_projects.filter(status='IN_PROGRESS').count(),
            'my_activities': ProjectActivity.objects.filter(project__client=request.user.cuser).select_related('project', 'created_by__user').prefetch_related('assigned_users__user'),
        })
    elif user_type == 'TECHNICIEN':
        # Technicien voit les activités de type NOTE
        context.update({
            'my_notes': ProjectActivity.objects.filter(
                activity_type='NOTE',
                assigned_to=request.user.cuser
            ).select_related('project', 'created_by__user').prefetch_related('assigned_users__user'),
            'assigned_projects': DashboardProject.objects.filter(
                assigned_technicians=request.user.cuser
            ),
        })
    
    return render(request, 'backoffice/dashboard/home.html', context)

@login_required(login_url="/auth/to_login")
def dashboard_projects_list(request):
    """Liste des projets selon le type d'utilisateur"""
    user_type = request.user.cuser.type
    
    if user_type == 'DRH':
        projects = DashboardProject.objects.all()
    elif user_type == 'CLIENT':
        projects = DashboardProject.objects.filter(client=request.user.cuser)
    elif user_type == 'TECHNICIEN':
        projects = DashboardProject.objects.filter(assigned_technicians=request.user.cuser)
    else:
        projects = DashboardProject.objects.none()
    
    # Filtres
    status_filter = request.GET.get('status')
    if status_filter:
        projects = projects.filter(status=status_filter)
    
    search = request.GET.get('search')
    if search:
        projects = projects.filter(
            Q(title__icontains=search) | 
            Q(description__icontains=search) |
            Q(client__user__first_name__icontains=search) |
            Q(client__user__last_name__icontains=search)
        )
    
    projects = projects.order_by('-created_at')
    
    # Optimization: prefetch related data
    projects = projects.select_related('client__user', 'created_by__user').prefetch_related('assigned_technicians__user')
    
    # Pagination
    paginator = Paginator(projects, 10)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'page_obj': page_obj,
        'user_type': user_type,
        'status_choices': DashboardProject.STATUS_CHOICES,
        'current_status': status_filter,
        'search_query': search,
        'page_title': 'Mes Projets' if user_type == 'CLIENT' else 'Projets',
    }
    
    return render(request, 'backoffice/dashboard/projects_list.html', context)

@login_required(login_url="/auth/to_login")
def dashboard_project_detail(request, project_id):
    """Détail d'un projet"""
    user_type = request.user.cuser.type
    
    if user_type == 'DRH':
        project = get_object_or_404(DashboardProject, id=project_id)
    elif user_type == 'CLIENT':
        project = get_object_or_404(DashboardProject, id=project_id, client=request.user.cuser)
    elif user_type == 'TECHNICIEN':
        project = get_object_or_404(DashboardProject, id=project_id, assigned_technicians=request.user.cuser)
    else:
        return redirect('app:dashboard_home')
    
    # Filtrer les activités selon le type d'utilisateur
    if user_type == 'DRH':
        activities = project.activities.all()
    elif user_type == 'CLIENT':
        activities = project.activities.all()
    elif user_type == 'TECHNICIEN':
        activities = project.activities.filter(activity_type='NOTE')
    
    activities = activities.order_by('-created_at')
    
    context = {
        'project': project,
        'activities': activities,
        'user_type': user_type,
        'page_title': f'Projet: {project.title}',
    }
    
    return render(request, 'backoffice/dashboard/project_detail.html', context)

@login_required(login_url="/auth/to_login")
def dashboard_activity_detail(request, activity_id):
    """Détail d'une activité"""
    user_type = request.user.cuser.type
    
    if user_type == 'DRH':
        activity = get_object_or_404(ProjectActivity, id=activity_id)
    elif user_type == 'CLIENT':
        activity = get_object_or_404(ProjectActivity, id=activity_id, project__client=request.user.cuser)
    elif user_type == 'TECHNICIEN':
        activity = get_object_or_404(ProjectActivity, id=activity_id, activity_type='NOTE')
    else:
        return redirect('app:dashboard_home')
    
    context = {
        'activity': activity,
        'user_type': user_type,
        'page_title': f'Activité: {activity.title}',
        'images': activity.images.all().order_by('order'),
        'videos': activity.videos.all().order_by('order'),
        'files': activity.files.all().order_by('-created_at'),
    }

    return render(request, 'backoffice/dashboard/activity_detail_new.html', context)

@login_required(login_url="/auth/to_login")
def dashboard_users_management(request):
    """Gestion des utilisateurs (DRH uniquement)"""
    if request.user.cuser.type != 'DRH':
        return redirect('app:dashboard_home')
    
    users = CostumUser.objects.select_related('user').all()
    
    # Filtres
    user_type_filter = request.GET.get('type')
    if user_type_filter:
        users = users.filter(type=user_type_filter)
    
    search = request.GET.get('search')
    if search:
        users = users.filter(
            Q(user__username__icontains=search) |
            Q(user__first_name__icontains=search) |
            Q(user__last_name__icontains=search) |
            Q(user__email__icontains=search)
        )
    
    users = users.order_by('-user__date_joined')
    
    # Statistiques par rôle
    total_users = CostumUser.objects.count()
    drh_count = CostumUser.objects.filter(type='DRH').count()
    client_count = CostumUser.objects.filter(type='CLIENT').count()
    technicien_count = CostumUser.objects.filter(type='TECHNICIEN').count()
    
    # Pagination
    paginator = Paginator(users, 15)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'page_obj': page_obj,
        'user_types': USER_TYPE,
        'current_type': user_type_filter,
        'search_query': search,
        'page_title': 'Gestion des utilisateurs',
        'total_users': total_users,
        'drh_count': drh_count,
        'client_count': client_count,
        'technicien_count': technicien_count,
    }
    
    return render(request, 'backoffice/dashboard/users_management.html', context)

@login_required(login_url="/auth/to_login")
def create_dashboard_user(request):
    """Créer un nouvel utilisateur (DRH uniquement)"""
    if request.user.cuser.type != 'DRH':
        return JsonResponse({'success': False, 'error': 'Accès refusé'})
    
    if request.method != 'POST':
        return JsonResponse({'success': False, 'error': f'Méthode {request.method} non autorisée. Utilisez POST.'})
    
    try:
        data = json.loads(request.body)
        email = data.get('email', '').strip().lower()
        first_name = data.get('first_name', '').strip()
        last_name = data.get('last_name', '').strip()
        user_type = data.get('user_type', '').strip()
        phone = data.get('phone', '').strip()
        
        # Validation des données
        if not email or not user_type:
            return JsonResponse({'success': False, 'error': 'Email et type d\'utilisateur requis'})
        
        # Vérifier que l'email n'existe pas déjà
        if User.objects.filter(email=email).exists():
            return JsonResponse({'success': False, 'error': 'Cet email est déjà utilisé'})
        
        if User.objects.filter(username=email).exists():
            return JsonResponse({'success': False, 'error': 'Cet email est déjà utilisé comme nom d\'utilisateur'})
        
        # Vérifier que le type est valide
        valid_types = [choice[0] for choice in USER_TYPE]
        if user_type not in valid_types:
            return JsonResponse({'success': False, 'error': 'Type d\'utilisateur invalide'})
        
        with transaction.atomic():
            # Créer l'utilisateur Django
            user = User.objects.create_user(
                username=email,
                email=email,
                first_name=first_name,
                last_name=last_name,
                is_active=True  # L'utilisateur sera activé après configuration du mot de passe
            )
            
            # Créer ou récupérer le profil CostumUser
            cuser, created = CostumUser.objects.get_or_create(
                user=user,
                defaults={
                    'type': user_type,
                    'phone': phone if phone else None
                }
            )
            
            # Si le profil existait déjà (créé par signal), le mettre à jour
            if not created:
                cuser.type = user_type
                cuser.phone = phone if phone else None
                cuser.save() 
        
            # Envoyer l'email
            try:
                message = """
                Voici le lien pour mettre à jour votre mot de passe

                """

                url = "/auth/to_updatepass/{}/{}/".format(
                    urlsafe_base64_encode(force_bytes(user.pk)),
                    account_activation_token.make_token(user),
                )

                print(url)
                to_email = user.email
                subject = "Réinitialiser mon mot de passe"
                cta = "Réinitialiser "
                
                send_my_mail(request, subject, message, [to_email], user, cta, url=url)

                return JsonResponse({'success': True, 'message': 'Utilisateur créé et email envoyé avec succès'})
                
            except Exception as e:
                # Supprimer l'utilisateur si l'email n'a pas pu être envoyé
                user.delete()
                return JsonResponse({
                    'success': False, 
                    'error': f'Erreur lors de l\'envoi de l\'email: {str(e)}'
                })
                
    except json.JSONDecodeError:
        return JsonResponse({'success': False, 'error': 'Données JSON invalides'})
    except Exception as e:
        return JsonResponse({'success': False, 'error': f'Erreur: {str(e)}'})

@login_required(login_url="/auth/to_login")
def dashboard_profile(request):
    """Profil utilisateur"""
    context = {
        'page_title': 'Mon Compte',
        'user_profile': request.user.cuser,
    }
    
    if request.method == 'POST':
        # Traitement de la mise à jour du profil
        user = request.user
        profile = user.cuser
        
        # Mise à jour des informations de base
        user.first_name = request.POST.get('first_name', '')
        user.last_name = request.POST.get('last_name', '')
        user.email = request.POST.get('email', '')
        profile.phone = request.POST.get('phone', '')
        profile.address = request.POST.get('address', '')
        
        # Gestion de l'image de profil
        if 'image' in request.FILES:
            profile.image = request.FILES['image']
        
        try:
            user.save()
            profile.save()
            messages.success(request, 'Profil mis à jour avec succès!')
        except Exception as e:
            messages.error(request, f'Erreur lors de la mise à jour: {str(e)}')
        
        return redirect('app:dashboard_profile')
    
    return render(request, 'backoffice/dashboard/profile.html', context)


# ================================
# VUES AJAX POUR GESTION PROJETS
# ================================

def generate_default_activities(project, template, parent=None, created_by=None):
    """
    Génère récursivement les activités par défaut pour un projet à partir d'un template
    
    Args:
        project: Instance de DashboardProject
        template: Liste de dictionnaires contenant la structure des activités
        parent: Activité parente (None pour les activités de niveau supérieur)
        created_by: Instance de CostumUser qui crée les activités
    """
    for activity_data in template:
        # Créer l'activité
        activity = ProjectActivity.objects.create(
            project=project,
            title=activity_data['title'],
            activity_type=activity_data.get('activity_type', 'CONSTRUCTION'),
            priority=activity_data.get('priority', 'MEDIUM'),
            description=activity_data.get('description', ''),
            parent=parent,
            created_by=created_by
        )
        
        # Si l'activité a des enfants, les créer récursivement
        if 'children' in activity_data and activity_data['children']:
            generate_default_activities(
                project=project,
                template=activity_data['children'],
                parent=activity,
                created_by=created_by
            )


def create_dashboard_project(request):
    """Créer un nouveau projet (DRH et TECHNICIEN uniquement)"""
    if request.user.cuser.type not in ['DRH', 'TECHNICIEN']:
        return JsonResponse({'error': 'Permission refusée'}, status=403)
    
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            
            # Validation des données
            required_fields = ['title', 'description', 'client_id']
            for field in required_fields:
                if field not in data or not data[field]:
                    return JsonResponse({'error': f'Champ manquant: {field}'}, status=400)
            
            # Vérifier que le client existe
            try:
                client = CostumUser.objects.get(id=data['client_id'], type='CLIENT')
            except CostumUser.DoesNotExist:
                return JsonResponse({'error': 'Client introuvable'}, status=400)
            
            # Créer le projet
            project = DashboardProject.objects.create(
                title=data['title'],
                description=data['description'],
                client=client,
                budget=data.get('budget'),
                start_date=data.get('start_date'),
                end_date=data.get('end_date'),
                status=data.get('status', 'PLANNING'),
                project_type=data.get('project_type', 'RESIDENTIEL'),
                created_by=request.user.cuser
            )

            # Catégorie (optionnelle)
            category_id = data.get('category_id')
            if category_id:
                try:
                    category = ProjectCategory.objects.get(id=category_id)
                    project.category = category
                    project.save(update_fields=['category'])
                except ProjectCategory.DoesNotExist:
                    pass
            
            # Gestion des techniciens assignés
            assigned_technicians = data.get('assigned_technicians', [])
            if assigned_technicians:
                # Valider que tous les IDs correspondent à des techniciens
                valid_technicians = CostumUser.objects.filter(
                    id__in=assigned_technicians, 
                    type='TECHNICIEN'
                )
                project.assigned_technicians.set(valid_technicians)
            
            # Générer automatiquement les activités par défaut pour le projet
            from .project_activities_template import PROJECT_ACTIVITIES_TEMPLATE
            generate_default_activities(
                project=project,
                template=PROJECT_ACTIVITIES_TEMPLATE,
                created_by=request.user.cuser
            )
            
            # Notifications
            send_project_notifications(project, 'created')
            
            return JsonResponse({
                'success': True,
                'project_id': project.id,
                'message': 'Projet créé avec succès'
            })
            
        except json.JSONDecodeError:
            return JsonResponse({'error': 'Format JSON invalide'}, status=400)
        except Exception as e:
            return JsonResponse({'error': f'Erreur: {str(e)}'}, status=500)
    
    return JsonResponse({'error': 'Méthode non autorisée'}, status=405)


@login_required(login_url="/auth/to_login")
@csrf_exempt
def delete_dashboard_project(request, project_id):
    """Supprimer un projet (DRH et ADMIN uniquement)"""
    # Vérifier les permissions - Seulement DRH et ADMIN peuvent supprimer
    if request.user.cuser.type not in ['DRH', 'ADMIN']:
        return JsonResponse({'error': 'Permission refusée. Seuls les DRH et ADMIN peuvent supprimer des projets.'}, status=403)
    
    if request.method == 'DELETE':
        try:
            # Récupérer le projet
            try:
                project = DashboardProject.objects.get(id=project_id)
            except DashboardProject.DoesNotExist:
                return JsonResponse({'error': 'Projet introuvable'}, status=404)
            
            # Stocker les informations avant suppression pour le log
            project_title = project.title
            project_client = project.client.user.get_full_name() if project.client else 'N/A'
            
            # Supprimer le projet (Django supprimera automatiquement les activités liées grâce à on_delete=CASCADE)
            project.delete()
            
            # Log de la suppression
            print(f"✅ Projet '{project_title}' (ID: {project_id}) supprimé par {request.user.username} ({request.user.cuser.type})")
            
            return JsonResponse({
                'success': True,
                'message': f'Projet "{project_title}" supprimé avec succès'
            })
            
        except Exception as e:
            print(f"❌ Erreur lors de la suppression du projet {project_id}: {str(e)}")
            return JsonResponse({'error': f'Erreur lors de la suppression: {str(e)}'}, status=500)
    
    return JsonResponse({'error': 'Méthode non autorisée'}, status=405)


@login_required(login_url="/auth/to_login")
def get_clients_list(request):
    """Récupérer la liste des clients pour les formulaires"""
    if request.user.cuser.type not in ['DRH', 'TECHNICIEN']:
        return JsonResponse({'error': 'Permission refusée'}, status=403)
    
    clients = CostumUser.objects.filter(type='CLIENT').select_related('user')
    clients_data = []
    
    for client in clients:
        clients_data.append({
            'id': client.id,
            'name': client.user.get_full_name() or client.user.username,
            'email': client.user.email,
        })
    
    return JsonResponse({
        'success': True,
        'clients': clients_data
    })


@login_required(login_url="/auth/to_login")
def get_project_categories(request):
    """Récupérer la liste des catégories de projet"""
    if request.user.cuser.type not in ['DRH', 'TECHNICIEN']:
        return JsonResponse({'error': 'Permission refusée'}, status=403)

    cats = ProjectCategory.objects.all().order_by('name')
    return JsonResponse({
        'success': True,
        'categories': [{'id': c.id, 'name': c.name} for c in cats]
    })


@login_required(login_url="/auth/to_login")
def get_technicians_list(request):
    """Récupérer la liste des techniciens pour les formulaires"""
    if request.user.cuser.type not in ['DRH', 'TECHNICIEN']:
        return JsonResponse({'error': 'Permission refusée'}, status=403)
    
    technicians = CostumUser.objects.filter(type='TECHNICIEN').select_related('user')
    technicians_data = []
    
    for tech in technicians:
        technicians_data.append({
            'id': tech.id,
            'name': tech.user.get_full_name() or tech.user.username,
            'email': tech.user.email,
        })
    
    return JsonResponse({
        'success': True,
        'technicians': technicians_data
    })


@login_required(login_url="/auth/to_login")
def get_drh_list(request):
    """Récupérer la liste des DRH pour assignation"""
    if request.user.cuser.type not in ['DRH', 'TECHNICIEN']:
        return JsonResponse({'error': 'Permission refusée'}, status=403)

    drh_users = CostumUser.objects.filter(type='DRH').select_related('user')
    data = [{'id': u.id, 'name': u.user.get_full_name() or u.user.username, 'email': u.user.email} for u in drh_users]
    return JsonResponse({'success': True, 'drh': data})


@login_required(login_url="/auth/to_login")
def get_project_data(request, project_id):
    """Récupérer les données d'un projet pour modification"""
    if request.user.cuser.type not in ['DRH', 'TECHNICIEN']:
        return JsonResponse({'error': 'Permission refusée'}, status=403)
    
    try:
        project = get_object_or_404(DashboardProject, id=project_id)
        
        project_data = {
            'id': project.id,
            'title': project.title,
            'description': project.description,
            'client_id': project.client.id,
            'budget': float(project.budget) if project.budget else None,
            'status': project.status,
            'start_date': project.start_date.isoformat() if project.start_date else None,
            'end_date': project.end_date.isoformat() if project.end_date else None,
            'assigned_technicians': list(project.assigned_technicians.values_list('id', flat=True)),
            'category_id': project.category.id if getattr(project, 'category', None) else None,
            'project_type': project.project_type,
        }
        
        return JsonResponse({
            'success': True,
            'project': project_data
        })
        
    except Exception as e:
        return JsonResponse({
            'success': False,
            'message': f'Erreur lors du chargement du projet: {str(e)}'
        })


@login_required(login_url="/auth/to_login")
@csrf_exempt
def update_dashboard_project(request):
    """Mettre à jour un projet existant"""
    if request.method == 'POST':
        if request.user.cuser.type not in ['DRH', 'TECHNICIEN']:
            return JsonResponse({'error': 'Permission refusée'}, status=403)
        
        try:
            data = json.loads(request.body)
            project_id = data.get('project_id')
            
            if not project_id:
                return JsonResponse({
                    'success': False,
                    'message': 'ID du projet manquant'
                })
            
            project = get_object_or_404(DashboardProject, id=project_id)
            
            # Vérifications de base
            if not data.get('title') or not data.get('description'):
                return JsonResponse({
                    'success': False,
                    'message': 'Le titre et la description sont obligatoires'
                })
            
            # Récupérer le client
            client_id = data.get('client_id')
            if client_id:
                try:
                    client = CostumUser.objects.get(id=client_id, type='CLIENT')
                    project.client = client
                except CostumUser.DoesNotExist:
                    return JsonResponse({
                        'success': False,
                        'message': 'Client non trouvé'
                    })
            
            # Mise à jour des champs
            project.title = data.get('title')
            project.description = data.get('description')
            project.status = data.get('status', 'PLANNING')

            # Catégorie et type de projet
            category_id = data.get('category_id')
            if category_id:
                try:
                    project.category = ProjectCategory.objects.get(id=category_id)
                except ProjectCategory.DoesNotExist:
                    project.category = None
            else:
                project.category = None

            project.project_type = data.get('project_type', project.project_type or 'RESIDENTIEL')
            
            # Budget (optionnel)
            budget = data.get('budget')
            if budget:
                try:
                    project.budget = Decimal(str(budget))
                except (ValueError, TypeError):
                    project.budget = None
            else:
                project.budget = None
            
            # Dates (optionnelles)
            start_date = data.get('start_date')
            if start_date:
                try:
                    project.start_date = parse_date(start_date)
                except (ValueError, TypeError):
                    project.start_date = None
            else:
                project.start_date = None
                
            end_date = data.get('end_date')
            if end_date:
                try:
                    project.end_date = parse_date(end_date)
                except (ValueError, TypeError):
                    project.end_date = None
            else:
                project.end_date = None
            
            # Gestion des techniciens assignés
            assigned_technicians = data.get('assigned_technicians', [])
            if assigned_technicians:
                # Valider que tous les IDs correspondent à des techniciens
                valid_technicians = CostumUser.objects.filter(
                    id__in=assigned_technicians, 
                    type='TECHNICIEN'
                )
                project.assigned_technicians.set(valid_technicians)
            else:
                project.assigned_technicians.clear()
            
            project.save()
            
            # Notifications
            send_project_notifications(project, 'updated')
            
            return JsonResponse({
                'success': True,
                'message': 'Projet mis à jour avec succès'
            })
            
        except json.JSONDecodeError:
            return JsonResponse({'error': 'Format JSON invalide'}, status=400)
        except Exception as e:
            return JsonResponse({
                'success': False,
                'message': f'Erreur: {str(e)}'
            })
    
    return JsonResponse({'error': 'Méthode non autorisée'}, status=405)


@login_required(login_url="/auth/to_login")
@csrf_exempt
def create_dashboard_activity(request):
    """Créer une nouvelle activité avec gestion des fichiers et permissions par rôle"""
    if request.method == 'POST':
        user_type = request.user.cuser.type
        
        if user_type not in ['DRH', 'TECHNICIEN', 'CLIENT']:
            return JsonResponse({'error': 'Permission refusée'}, status=403)
        
        try:
            # Récupérer les données du formulaire
            project_id = request.POST.get('project_id')
            
            if not project_id:
                return JsonResponse({
                    'success': False,
                    'message': 'ID du projet manquant'
                })
            
            # Vérifications de base
            title = request.POST.get('title')
            description = request.POST.get('description')
            activity_type = request.POST.get('activity_type')
            
            if not title or not description or not activity_type:
                return JsonResponse({
                    'success': False,
                    'message': 'Le titre, la description et le type d\'activité sont obligatoires'
                })
            
            # Récupérer le projet
            project = get_object_or_404(DashboardProject, id=project_id)
            
            # Vérifier les permissions pour ce projet selon le rôle
            if user_type == 'TECHNICIEN':
                if not project.assigned_technicians.filter(id=request.user.cuser.id).exists():
                    return JsonResponse({
                        'success': False,
                        'message': 'Vous n\'êtes pas autorisé à créer des activités pour ce projet'
                    })
                # Vérifier que le type d'activité est autorisé pour les techniciens
                allowed_types = ['NOTE', 'DESIGN', 'CONSTRUCTION', 'PLANNING', 'INSPECTION', 'DOCUMENTATION', 'MEETING']
                if activity_type not in allowed_types:
                    return JsonResponse({
                        'success': False,
                        'message': 'Type d\'activité non autorisé pour votre rôle'
                    })
            elif user_type == 'CLIENT':
                # Vérifier que c'est le client du projet
                if project.client.id != request.user.cuser.id:
                    return JsonResponse({
                        'success': False,
                        'message': 'Vous n\'êtes pas autorisé à créer des activités pour ce projet'
                    })
                # Vérifier que le type d'activité est autorisé pour les clients
                allowed_types = ['NOTE', 'JUSTIFICATIF']
                if activity_type not in allowed_types:
                    return JsonResponse({
                        'success': False,
                        'message': 'Type d\'activité non autorisé pour votre rôle'
                    })
            # Les DRH ont accès à tous les types d'activités
            
            # Créer l'activité
            activity = ProjectActivity(
                project=project,
                title=title,
                description=description,
                activity_type=activity_type,
                priority=request.POST.get('priority', 'MEDIUM'),
                created_by=request.user.cuser
            )

            # Nouveaux champs optionnels
            parent_id = request.POST.get('parent') or request.POST.get('parent_id')
            if parent_id:
                try:
                    activity.parent = ProjectActivity.objects.get(id=parent_id, project=project)
                except ProjectActivity.DoesNotExist:
                    pass

            billing_type = request.POST.get('billing_type')
            if billing_type in dict(ProjectActivity.BILLING_TYPE_CHOICES).keys():
                activity.billing_type = billing_type

            budget_amount = request.POST.get('budget_amount')
            if budget_amount:
                try:
                    activity.budget_amount = Decimal(str(budget_amount))
                except Exception:
                    activity.budget_amount = None

            is_active = request.POST.get('is_active')
            if is_active is not None:
                activity.is_active = str(is_active).lower() in ('1', 'true', 'yes', 'on')
            
            # Assignation multiple (nouvelle fonctionnalité)
            assigned_users = request.POST.getlist('assigned_to')
            if assigned_users:
                try:
                    # Permettre l'assignation à plusieurs utilisateurs
                    valid_users = CostumUser.objects.filter(id__in=assigned_users)
                    if valid_users.exists():
                        # Pour compatibilité, garder le premier assigné dans assigned_to
                        activity.assigned_to = valid_users.first()
                        
                except Exception as e:
                    pass  # Ignorer les erreurs d'assignation
            
            # Date d'échéance (optionnelle)
            due_date = request.POST.get('due_date')
            if due_date:
                try:
                    activity.due_date = parse_date(due_date)
                except (ValueError, TypeError):
                    activity.due_date = None
            
            activity.save()
            
            # Assigner les utilisateurs multiples après la sauvegarde
            if assigned_users:
                try:
                    valid_users = CostumUser.objects.filter(id__in=assigned_users)
                    activity.assigned_users.set(valid_users)
                except Exception as e:
                    pass  # Ignorer les erreurs d'assignation
            
            # Traiter les fichiers joints
            files = request.FILES.getlist('activity_files')
            for file in files:
                # Déterminer le type de fichier
                if file.content_type.startswith('image/'):
                    # Créer une ActivityImage
                    ActivityImage.objects.create(
                        activity=activity,
                        image=file,
                        title=file.name,
                        description=f"Image ajoutée lors de la création de l'activité"
                    )
                elif file.content_type.startswith('video/'):
                    # Créer une ActivityVideo
                    ActivityVideo.objects.create(
                        activity=activity,
                        title=file.name,
                        video_type='FILE',
                        video_file=file,
                        description=f"Vidéo ajoutée lors de la création de l'activité"
                    )
                else:
                    # Créer un ActivityFile pour les autres types
                    ActivityFile.objects.create(
                        activity=activity,
                        title=file.name,
                        file=file,
                        description=f"Document ajouté lors de la création de l'activité",
                        uploaded_by=request.user.cuser
                    )
            
            # Notifications
            send_activity_notifications(activity, 'created')
            
            return JsonResponse({
                'success': True,
                'message': f'Activité créée avec succès. {len(files)} fichier(s) ajouté(s).' if files else 'Activité créée avec succès.'
            })
            
        except Exception as e:
            return JsonResponse({
                'success': False,
                'message': f'Erreur: {str(e)}'
            })
    
    return JsonResponse({'error': 'Méthode non autorisée'}, status=405)


@login_required(login_url="/auth/to_login")
def test_notifications(request):
    """Page de test pour le système de notifications"""
    if request.user.cuser.type not in ['DRH', 'TECHNICIEN']:
        return redirect('app:dashboard_home')
    
    return render(request, 'backoffice/dashboard/test_notifications.html', {
        'page_title': 'Test Notifications'
    })


@login_required(login_url="/auth/to_login")
def project_activities(request, project_id):
    """Page des activités d'un projet avec filtrage selon les rôles"""
    try:
        project = get_object_or_404(DashboardProject.objects.select_related('created_by__user'), id=project_id)
        user_type = request.user.cuser.type
        
        # Vérification des permissions d'accès au projet
        if user_type == 'TECHNICIEN':
            # Les techniciens ne peuvent voir que les projets qui leur sont assignés
            if not project.assigned_technicians.filter(id=request.user.cuser.id).exists():
                messages.error(request, "Vous n'avez pas accès à ce projet.")
                return redirect('app:dashboard_projects_list')
        elif user_type == 'CLIENT':
            # Les clients ne peuvent voir que leurs propres projets
            if project.client.id != request.user.cuser.id:
                messages.error(request, "Vous n'avez pas accès à ce projet.")
                return redirect('app:dashboard_home')
        elif user_type not in ['DRH', 'TECHNICIEN', 'CLIENT']:
            messages.error(request, "Accès non autorisé.")
            return redirect('app:dashboard_home')
        
        # Filtrage des activités selon le rôle
        activities = project.activities.select_related('created_by__user', 'assigned_to__user').prefetch_related('assigned_users__user')
        
        if user_type == 'TECHNICIEN':
            # Les techniciens ne voient pas les activités de type FACTURE, DEVIS, JUSTIFICATIF
            activities = activities.exclude(activity_type__in=['FACTURE', 'DEVIS', 'JUSTIFICATIF'])
        elif user_type == 'CLIENT':
            # Les clients peuvent voir toutes les activités de leurs projets
            pass  # Pas de filtrage particulier pour les clients
        
        # Trier par date de création (plus récent en premier)
        activities = activities.order_by('-created_at')

        # Regroupement parent -> enfants
        activities_list = list(activities)
        root_activities = [a for a in activities_list if getattr(a, 'parent_id', None) is None]
        children_by_parent = {}
        for a in activities_list:
            if getattr(a, 'parent_id', None):
                children_by_parent.setdefault(a.parent_id, []).append(a)

        # Conserver l'ordre (déjà trié) dans les groupes
        activity_groups = []
        for root in root_activities:
            activity_groups.append({
                'parent': root,
                'children': children_by_parent.get(root.id, [])
            })
        
        # Statistiques
        total_activities = activities.count()
        completed_activities = activities.filter(is_completed=True).count()
        pending_activities = activities.filter(is_completed=False).count()
        overdue_activities = activities.filter(
            is_completed=False,
            due_date__lt=timezone.now().date()
        ).count()
        
        # Permissions pour les actions
        can_create_activity = user_type in ['DRH', 'TECHNICIEN', 'CLIENT']
        can_edit_activity = user_type in ['DRH', 'TECHNICIEN']
        
        # Types d'activités autorisés selon le rôle
        if user_type == 'DRH':
            allowed_activity_types = ProjectActivity.ACTIVITY_TYPES
        elif user_type == 'TECHNICIEN':
            allowed_activity_types = [
                ('NOTE', 'Note'),
                ('DESIGN', 'Design/Conception'),
                ('CONSTRUCTION', 'Construction'),
                ('PLANNING', 'Planification'),
                ('INSPECTION', 'Inspection'),
                ('DOCUMENTATION', 'Documentation'),
                ('MEETING', 'Réunion'),
            ]
        elif user_type == 'CLIENT':
            allowed_activity_types = [
                ('NOTE', 'Note'),
                ('JUSTIFICATIF', 'Justificatif'),
            ]
        else:
            allowed_activity_types = []
        
        # Techniciens disponibles pour l'assignation
        available_technicians = project.assigned_technicians.all()
        
        # Récupérer tous les utilisateurs disponibles pour l'assignation
        all_users = CostumUser.objects.select_related('user').exclude(
            user__is_active=False
        ).order_by('type', 'user__first_name', 'user__last_name')
        
        context = {
            'project': project,
            'activities': activities,
            'activity_groups': activity_groups,
            'total_activities': total_activities,
            'completed_activities': completed_activities,
            'pending_activities': pending_activities,
            'overdue_activities': overdue_activities,
            'can_create_activity': can_create_activity,
            'can_edit_activity': can_edit_activity,
            'allowed_activity_types': allowed_activity_types,
            'available_technicians': available_technicians,
            'all_users': all_users,
            'user_type': user_type,
            'page_title': f'Activités - {project.title}'
        }
        
        return render(request, 'backoffice/dashboard/project_activities.html', context)
        
    except Exception as e:
        messages.error(request, f"Erreur lors du chargement des activités: {str(e)}")
        return redirect('app:dashboard_projects_list')


@login_required(login_url="/auth/to_login")
def get_activity_data(request, activity_id):
    """Retourner les détails d'une activité (pour édition)"""
    activity = get_object_or_404(ProjectActivity.objects.select_related('created_by__user', 'project'), id=activity_id)
    # Permission de lecture: visible si utilisateur a accès au projet (mêmes règles que page)
    project = activity.project
    user_type = request.user.cuser.type
    if user_type == 'TECHNICIEN' and not project.assigned_technicians.filter(id=request.user.cuser.id).exists():
        return JsonResponse({'success': False, 'message': "Accès refusé"}, status=403)
    if user_type == 'CLIENT' and project.client.id != request.user.cuser.id:
        return JsonResponse({'success': False, 'message': "Accès refusé"}, status=403)

    data = {
        'id': activity.id,
        'title': activity.title,
        'description': activity.description or '',
        'activity_type': activity.activity_type,
        'priority': activity.priority,
        'due_date': activity.due_date.isoformat() if activity.due_date else None,
        'parent_id': activity.parent_id,
        'billing_type': activity.billing_type,
        'budget_amount': str(activity.budget_amount) if activity.budget_amount is not None else None,
        'is_active': activity.is_active,
        'assigned_user_ids': list(activity.assigned_users.values_list('id', flat=True)) or ([activity.assigned_to_id] if activity.assigned_to_id else []),
        # Ajouter les fichiers existants avec leurs IDs
        'images': [{'id': img.id, 'url': img.image.url, 'name': img.title or 'Image'} for img in activity.images.all()],
        'files': [{'id': f.id, 'url': f.file.url, 'name': f.title or 'Fichier'} for f in activity.files.all()],
        'videos': [{'id': v.id, 'url': v.video_file.url if v.video_file else v.video_url, 'name': v.title or 'Vidéo'} for v in activity.videos.all()],
    }
    return JsonResponse({'success': True, 'activity': data})


@login_required(login_url="/auth/to_login")
@csrf_exempt
def update_dashboard_activity(request, activity_id):
    """Mettre à jour une activité existante"""
    if request.method != 'POST':
        return JsonResponse({'error': 'Méthode non autorisée'}, status=405)

    activity = get_object_or_404(ProjectActivity, id=activity_id)
    user_type = request.user.cuser.type
    # Permissions: DRH, propriétaire (créateur) ou superuser
    if not (user_type == 'DRH' or activity.created_by_id == request.user.cuser.id or request.user.is_superuser):
        return JsonResponse({'success': False, 'message': 'Permission refusée'}, status=403)

    # Accepter FormData (multipart) pour fichiers éventuels ou JSON
    if request.content_type and 'application/json' in request.content_type:
        try:
            payload = json.loads(request.body.decode('utf-8'))
        except Exception:
            payload = {}
        getv = lambda k, default=None: payload.get(k, default)
        getlist = lambda k: payload.get(k, []) if isinstance(payload.get(k), list) else ([] if payload.get(k) is None else [payload.get(k)])
    else:
        getv = lambda k, default=None: request.POST.get(k, default)
        getlist = lambda k: request.POST.getlist(k)

    title = getv('title')
    description = getv('description')
    activity_type = getv('activity_type')
    priority = getv('priority', activity.priority)
    due_date = getv('due_date')
    billing_type = getv('billing_type')
    budget_amount = getv('budget_amount')
    is_active = getv('is_active')
    parent_id = getv('parent') or getv('parent_id')
    assigned_users = getlist('assigned_to')

    if title: activity.title = title
    if description is not None: activity.description = description
    if activity_type: activity.activity_type = activity_type
    if priority: activity.priority = priority

    if due_date:
        try:
            activity.due_date = parse_date(due_date)
        except Exception:
            pass

    if billing_type in dict(ProjectActivity.BILLING_TYPE_CHOICES).keys():
        activity.billing_type = billing_type

    if budget_amount is not None and budget_amount != '':
        try:
            activity.budget_amount = Decimal(str(budget_amount))
        except Exception:
            activity.budget_amount = None

    if is_active is not None:
        activity.is_active = str(is_active).lower() in ('1','true','yes','on')

    if parent_id:
        try:
            parent = ProjectActivity.objects.get(id=parent_id, project=activity.project)
            # éviter parent=soi-même
            if parent.id != activity.id:
                activity.parent = parent
        except ProjectActivity.DoesNotExist:
            pass
    elif parent_id == '' or parent_id is None:
        activity.parent = None

    activity.save()

    # Supprimer les fichiers marqués pour suppression
    delete_images = getv('delete_images')
    delete_files = getv('delete_files')
    delete_videos = getv('delete_videos')
    
    if delete_images:
        try:
            image_ids = json.loads(delete_images) if isinstance(delete_images, str) else delete_images
            if image_ids and len(image_ids) > 0:
                deleted_count = ActivityImage.objects.filter(id__in=image_ids, activity=activity).delete()
                print(f"Images supprimées: {deleted_count}")
        except Exception as e:
            print(f"Erreur suppression images: {e}")
    
    if delete_files:
        try:
            file_ids = json.loads(delete_files) if isinstance(delete_files, str) else delete_files
            if file_ids and len(file_ids) > 0:
                deleted_count = ActivityFile.objects.filter(id__in=file_ids, activity=activity).delete()
                print(f"Fichiers supprimés: {deleted_count}")
        except Exception as e:
            print(f"Erreur suppression fichiers: {e}")
    
    if delete_videos:
        try:
            video_ids = json.loads(delete_videos) if isinstance(delete_videos, str) else delete_videos
            if video_ids and len(video_ids) > 0:
                deleted_count = ActivityVideo.objects.filter(id__in=video_ids, activity=activity).delete()
                print(f"Vidéos supprimées: {deleted_count}")
        except Exception as e:
            print(f"Erreur suppression vidéos: {e}")

    # Mettre à jour l'assignation multiple
    if assigned_users:
        try:
            valid_users = CostumUser.objects.filter(id__in=assigned_users)
            activity.assigned_users.set(valid_users)
            if valid_users.exists():
                activity.assigned_to = valid_users.first()
                activity.save()
        except Exception:
            pass

    # Traiter les nouveaux fichiers joints (si présents)
    files = request.FILES.getlist('activity_files')
    for file in files:
        # Déterminer le type de fichier
        if file.content_type.startswith('image/'):
            # Créer une ActivityImage
            ActivityImage.objects.create(
                activity=activity,
                image=file,
                title=file.name,
                description=f"Image ajoutée lors de la modification de l'activité"
            )
        elif file.content_type.startswith('video/'):
            # Créer une ActivityVideo
            ActivityVideo.objects.create(
                activity=activity,
                title=file.name,
                video_type='FILE',
                video_file=file,
                description=f"Vidéo ajoutée lors de la modification de l'activité"
            )
        else:
            # Créer un ActivityFile pour les autres types (PDF, Word, etc.)
            ActivityFile.objects.create(
                activity=activity,
                file=file,
                title=file.name,
                description=f"Fichier ajouté lors de la modification de l'activité",
                uploaded_by=request.user.cuser  # Ajout de l'utilisateur qui uploade
            )

    return JsonResponse({'success': True, 'message': 'Activité mise à jour'})


@login_required(login_url="/auth/to_login")
@csrf_exempt
def delete_dashboard_activity(request, activity_id):
    """Supprimer une activité (autorisations: propriétaire, DRH, superuser)"""
    if request.method != 'POST':
        return JsonResponse({'error': 'Méthode non autorisée'}, status=405)

    activity = get_object_or_404(ProjectActivity, id=activity_id)
    user_type = request.user.cuser.type
    if not (request.user.is_superuser or user_type == 'DRH' or activity.created_by_id == request.user.cuser.id):
        return JsonResponse({'success': False, 'message': 'Permission refusée'}, status=403)

    activity.delete()
    return JsonResponse({'success': True, 'message': 'Activité supprimée'})


@login_required(login_url="/auth/to_login")
def get_project_activities_options(request, project_id):
    """Retourne la liste des activités (id, title) d'un projet pour les sélecteurs"""
    project = get_object_or_404(DashboardProject, id=project_id)
    # Permissions simples: DRH et TECHNICIEN sur projets assignés; client sur son projet
    user_type = request.user.cuser.type
    if user_type == 'TECHNICIEN' and not project.assigned_technicians.filter(id=request.user.cuser.id).exists():
        return JsonResponse({'error': 'Permission refusée'}, status=403)
    if user_type == 'CLIENT' and project.client.id != request.user.cuser.id:
        return JsonResponse({'error': 'Permission refusée'}, status=403)

    activities = project.activities.only('id', 'title').order_by('-created_at')
    return JsonResponse({'success': True, 'activities': [{'id': a.id, 'title': a.title} for a in activities]})


@login_required(login_url="/auth/to_login")
@csrf_exempt
def toggle_activity_status(request, activity_id):
    """Basculer le statut d'une activité (terminée/en cours)"""
    if request.method == 'POST':
        try:
            activity = get_object_or_404(ProjectActivity, id=activity_id)
            user_type = request.user.cuser.type
            
            # Vérifications de permissions
            if user_type == 'TECHNICIEN':
                # Vérifier que le technicien est assigné au projet
                if not activity.project.assigned_technicians.filter(id=request.user.cuser.id).exists():
                    return JsonResponse({'error': 'Permission refusée'}, status=403)
            elif user_type == 'CLIENT':
                # Vérifier que c'est le client du projet
                if activity.project.client.id != request.user.cuser.id:
                    return JsonResponse({'error': 'Permission refusée'}, status=403)
            elif user_type not in ['DRH']:
                return JsonResponse({'error': 'Permission refusée'}, status=403)
            
            # Mettre à jour le statut
            completed = request.POST.get('completed', 'false').lower() == 'true'
            activity.is_completed = completed
            activity.save()
            
            # Envoyer notification si l'activité est marquée comme terminée
            if completed:
                send_activity_notifications(activity, 'completed')
            
            return JsonResponse({
                'success': True,
                'message': f'Activité {"terminée" if completed else "remise en cours"} avec succès'
            })
            
        except Exception as e:
            return JsonResponse({
                'success': False,
                'message': f'Erreur: {str(e)}'
            })
    
    return JsonResponse({'error': 'Méthode non autorisée'}, status=405)


@login_required(login_url="/auth/to_login")
def project_finance(request, project_id):
    """Page Finance: agrège décomptes, factures, paiements et activités facturables"""
    project = get_object_or_404(DashboardProject, id=project_id)

    # Permissions: DRH et TECHNICIEN (assignés) et client (son projet)
    user_type = request.user.cuser.type
    if user_type == 'TECHNICIEN' and not project.assigned_technicians.filter(id=request.user.cuser.id).exists():
        messages.error(request, "Vous n'avez pas accès à ce projet.")
        return redirect('app:dashboard_projects_list')
    if user_type == 'CLIENT' and project.client.id != request.user.cuser.id:
        messages.error(request, "Vous n'avez pas accès à ce projet.")
        return redirect('app:dashboard_home')

    decomptes = project.decomptes.all().order_by('-date')
    invoices = project.invoices.all().order_by('-date')
    payments = project.payments.all().order_by('-date')
    billable_activities = project.activities.filter(billing_type__in=['MILESTONE', 'FIXED', 'TIME']).order_by('-created_at')

    # Règle: activité facturable terminée == considérée comme payée (affichage)
    completed_billable_count = billable_activities.filter(is_completed=True).count()

    context = {
        'project': project,
        'decomptes': decomptes,
        'invoices': invoices,
        'payments': payments,
        'billable_activities': billable_activities,
        'completed_billable_count': completed_billable_count,
        'page_title': f'Finance - {project.title}',
        'totals': {
            'decomptes': float(project.total_decomptes_amount or 0),
            'invoices': float(project.total_invoices_amount or 0),
            'payments': float(project.total_payments_amount or 0),
            'remaining': float(project.remaining_amount or 0),
            'percent_paid': project.percent_paid,
        }
    }

    return render(request, 'backoffice/dashboard/project_finance.html', context)

