from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework import status
from django.db import transaction
from django.db.models import Sum, Count, Min, Max, Q
from django.utils import timezone
from datetime import timedelta, datetime
from django.http import HttpResponse
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
from openpyxl.utils import get_column_letter
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, A4
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
import io
from .models import Project
from .serializers import ProjectSerializer
from stamps.models import Stamp
from tasks.models import Task
from user.models import User
from ErrorLogs.utils import log_error

@api_view(['GET', 'POST'])
@permission_classes([AllowAny])
def project_list(request):
    if request.method == 'GET':
        try:
            projects = Project.objects.all()
            serializer = ProjectSerializer(projects, many=True)
            return Response(serializer.data)
        except Exception as e:
            log_error('project_list.GET', e)
            return Response(
                {"error": "An error occurred while fetching projects"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    elif request.method == 'POST':
        try:
            with transaction.atomic():
                serializer = ProjectSerializer(data=request.data)
                if serializer.is_valid():
                    serializer.save()
                    return Response(serializer.data, status=status.HTTP_201_CREATED)
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            log_error('project_list.POST', e)
            return Response(
                {"error": "An error occurred while creating project"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

@api_view(['GET', 'PUT', 'DELETE'])
@permission_classes([AllowAny])
def project_detail(request, pk):
    try:
        project = Project.objects.get(pk=pk)
    except Project.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)
    except Exception as e:
        log_error('project_detail.get_project', e)
        return Response(
            {"error": "An error occurred while fetching project"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )

    if request.method == 'GET':
        try:
            serializer = ProjectSerializer(project)
            return Response(serializer.data)
        except Exception as e:
            log_error('project_detail.GET', e)
            return Response(
                {"error": "An error occurred while fetching project details"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    elif request.method == 'PUT':
        try:
            with transaction.atomic():
                serializer = ProjectSerializer(project, data=request.data)
                if serializer.is_valid():
                    serializer.save()
                    return Response(serializer.data)
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            log_error('project_detail.PUT', e)
            return Response(
                {"error": "An error occurred while updating project"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    elif request.method == 'DELETE':
        try:
            with transaction.atomic():
                project.delete()
                return Response(status=status.HTTP_204_NO_CONTENT)
        except Exception as e:
            log_error('project_detail.DELETE', e)
            return Response(
                {"error": "An error occurred while deleting project"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


def parse_duration_to_minutes(duration_str):
    """Parse duration string (HH:MM or decimal) to total minutes"""
    if not duration_str:
        return 0
    
    # Remove 'hrs' suffix if present
    duration_str = str(duration_str).replace('hrs', '').strip()
    
    # Try HH:MM format
    if ':' in duration_str:
        parts = duration_str.split(':')
        if len(parts) >= 2:
            try:
                hours = int(parts[0]) or 0
                minutes = int(parts[1]) or 0
                return (hours * 60) + minutes
            except (ValueError, IndexError):
                pass
    
    # Try decimal format (e.g., "8.5" hours)
    try:
        decimal_hours = float(duration_str)
        return int(decimal_hours * 60)
    except ValueError:
        return 0


def format_minutes_to_duration(total_minutes):
    """Format total minutes to HH:MM string"""
    if total_minutes == 0:
        return '00:00'
    hours = total_minutes // 60
    minutes = total_minutes % 60
    return f"{hours:02d}:{minutes:02d}"


@api_view(['GET'])
@permission_classes([AllowAny])
def project_analytics(request, pk):
    """Get analytics data for a specific project"""
    try:
        project = Project.objects.get(pk=pk)
    except Project.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)
    except Exception as e:
        log_error('project_analytics.get_project', e)
        return Response(
            {"error": "An error occurred while fetching project"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
    
    try:
        # Get all stamps for this project
        stamps = Stamp.objects.filter(project_id=pk).select_related('user', 'task')
        
        # Calculate total hours spent
        total_minutes = 0
        for stamp in stamps:
            if stamp.duration:
                total_minutes += parse_duration_to_minutes(stamp.duration)
        
        total_hours_formatted = format_minutes_to_duration(total_minutes)
        
        # Parse estimated time
        estimated_minutes = parse_duration_to_minutes(project.estimated_time) if project.estimated_time else 0
        
        # Calculate variance
        variance_minutes = total_minutes - estimated_minutes
        variance_formatted = format_minutes_to_duration(abs(variance_minutes))
        variance_percentage = (total_minutes / estimated_minutes * 100) if estimated_minutes > 0 else 0
        
        # Hours by employee
        hours_by_employee = {}
        for stamp in stamps:
            if stamp.duration and stamp.user:
                user_id = str(stamp.user.id)
                user_name = f"{stamp.user.firstname} {stamp.user.lastname}".strip()
                if user_id not in hours_by_employee:
                    hours_by_employee[user_id] = {
                        'user_id': user_id,
                        'user_name': user_name,
                        'total_minutes': 0,
                        'stamp_count': 0
                    }
                hours_by_employee[user_id]['total_minutes'] += parse_duration_to_minutes(stamp.duration)
                hours_by_employee[user_id]['stamp_count'] += 1
        
        # Format hours by employee
        employee_breakdown = []
        for user_data in hours_by_employee.values():
            employee_breakdown.append({
                'user_id': user_data['user_id'],
                'user_name': user_data['user_name'],
                'total_hours': format_minutes_to_duration(user_data['total_minutes']),
                'total_minutes': user_data['total_minutes'],
                'stamp_count': user_data['stamp_count'],
                'percentage': (user_data['total_minutes'] / total_minutes * 100) if total_minutes > 0 else 0
            })
        
        # Sort by total minutes descending
        employee_breakdown.sort(key=lambda x: x['total_minutes'], reverse=True)
        
        # Hours by task
        hours_by_task = {}
        for stamp in stamps:
            if stamp.duration and stamp.task:
                task_id = str(stamp.task.id)
                # Try to get task name, fallback to ID
                task_name = getattr(stamp.task, 'name', None) or getattr(stamp.task, 'code', None) or f"Task {task_id[:8]}"
                if task_id not in hours_by_task:
                    hours_by_task[task_id] = {
                        'task_id': task_id,
                        'task_name': task_name,
                        'total_minutes': 0,
                        'stamp_count': 0
                    }
                hours_by_task[task_id]['total_minutes'] += parse_duration_to_minutes(stamp.duration)
                hours_by_task[task_id]['stamp_count'] += 1
        
        # Format hours by task
        task_breakdown = []
        for task_data in hours_by_task.values():
            task_breakdown.append({
                'task_id': task_data['task_id'],
                'task_name': task_data['task_name'],
                'total_hours': format_minutes_to_duration(task_data['total_minutes']),
                'total_minutes': task_data['total_minutes'],
                'stamp_count': task_data['stamp_count'],
                'percentage': (task_data['total_minutes'] / total_minutes * 100) if total_minutes > 0 else 0
            })
        
        # Sort by total minutes descending
        task_breakdown.sort(key=lambda x: x['total_minutes'], reverse=True)
        
        # Timeline data
        first_stamp = stamps.order_by('date', 'time').first()
        last_stamp = stamps.order_by('-date', '-time').first()
        
        first_stamp_date = first_stamp.date if first_stamp else None
        last_stamp_date = last_stamp.date if last_stamp else None
        
        days_active = 0
        if first_stamp_date and last_stamp_date:
            days_active = (last_stamp_date - first_stamp_date).days + 1
        
        # Recent activity (stamps in last 7 and 30 days)
        today = timezone.now().date()
        seven_days_ago = today - timedelta(days=7)
        thirty_days_ago = today - timedelta(days=30)
        
        recent_stamps_7d = stamps.filter(date__gte=seven_days_ago).count()
        recent_stamps_30d = stamps.filter(date__gte=thirty_days_ago).count()
        
        # Active users (users with stamps in last 30 days)
        active_user_ids = stamps.filter(date__gte=thirty_days_ago).values_list('user_id', flat=True).distinct()
        active_users_count = len(set(active_user_ids))
        
        # Days since last activity
        days_since_last_activity = None
        if last_stamp_date:
            days_since_last_activity = (today - last_stamp_date).days
        
        # Average hours per day
        avg_hours_per_day = 0
        if days_active > 0:
            avg_minutes_per_day = total_minutes / days_active
            avg_hours_per_day = round(avg_minutes_per_day / 60, 2)
        
        # Weekly breakdown (last 12 weeks)
        weekly_breakdown = []
        for i in range(12):
            week_end = today - timedelta(weeks=i)
            week_start = week_end - timedelta(days=6)
            week_stamps = stamps.filter(date__gte=week_start, date__lte=week_end)
            week_minutes = sum(parse_duration_to_minutes(s.duration) for s in week_stamps if s.duration)
            weekly_breakdown.append({
                'week_start': week_start.isoformat(),
                'week_end': week_end.isoformat(),
                'total_hours': format_minutes_to_duration(week_minutes),
                'total_minutes': week_minutes,
                'stamp_count': week_stamps.count()
            })
        weekly_breakdown.reverse()  # Oldest to newest
        
        # Completion status
        status_indicator = 'on_track'
        status_message = 'On Track'
        if estimated_minutes > 0:
            if variance_percentage > 120:
                status_indicator = 'over_budget'
                status_message = 'Over Budget'
            elif variance_percentage > 110:
                status_indicator = 'at_risk'
                status_message = 'At Risk'
            elif variance_percentage < 80:
                status_indicator = 'under_budget'
                status_message = 'Under Budget'
        
        # Build response
        analytics_data = {
            'project_id': str(project.id),
            'project_name': project.name,
            'total_hours_spent': total_hours_formatted,
            'total_minutes': total_minutes,
            'estimated_hours': format_minutes_to_duration(estimated_minutes) if estimated_minutes > 0 else '00:00',
            'estimated_minutes': estimated_minutes,
            'variance': {
                'minutes': variance_minutes,
                'formatted': variance_formatted,
                'percentage': round(variance_percentage, 1),
                'is_over': variance_minutes > 0
            },
            'status': {
                'indicator': status_indicator,
                'message': status_message
            },
            'timeline': {
                'first_stamp_date': first_stamp_date.isoformat() if first_stamp_date else None,
                'last_stamp_date': last_stamp_date.isoformat() if last_stamp_date else None,
                'days_active': days_active,
                'days_since_last_activity': days_since_last_activity
            },
            'recent_activity': {
                'stamps_last_7_days': recent_stamps_7d,
                'stamps_last_30_days': recent_stamps_30d,
                'active_users_count': active_users_count
            },
            'efficiency': {
                'average_hours_per_day': avg_hours_per_day,
                'total_stamps': stamps.count()
            },
            'hours_by_employee': employee_breakdown,
            'hours_by_task': task_breakdown,
            'weekly_breakdown': weekly_breakdown
        }
        
        return Response(analytics_data)
        
    except Exception as e:
        log_error('project_analytics.calculate', e)
        return Response(
            {"error": "An error occurred while calculating project analytics"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )


def parse_duration_to_minutes(duration_str):
    """Parse duration string (HH:MM or decimal) to total minutes"""
    if not duration_str:
        return 0
    duration_str = str(duration_str).replace('hrs', '').strip()
    if ':' in duration_str:
        parts = duration_str.split(':')
        hours = int(parts[0]) if parts[0].isdigit() else 0
        minutes = int(parts[1]) if len(parts) > 1 and parts[1].isdigit() else 0
        return (hours * 60) + minutes
    else:
        try:
            decimal_hours = float(duration_str)
            return int(decimal_hours * 60)
        except ValueError:
            return 0


@api_view(['GET'])
@permission_classes([AllowAny])
def project_report(request):
    """
    Generate project report with task details, hours, and employee information
    Query params: project_id (optional - if not provided, returns all projects), start_date, end_date
    """
    try:
        project_id = request.query_params.get('project_id')
        start_date = request.query_params.get('start_date')
        end_date = request.query_params.get('end_date')
        
        # Parse date filters
        start_date_obj = None
        end_date_obj = None
        if start_date:
            try:
                start_date_obj = datetime.strptime(start_date, '%Y-%m-%d').date()
            except ValueError:
                pass
        if end_date:
            try:
                end_date_obj = datetime.strptime(end_date, '%Y-%m-%d').date()
            except ValueError:
                pass
        
        # Get projects
        if project_id:
            projects = Project.objects.filter(id=project_id)
        else:
            projects = Project.objects.all()
        
        project_reports = []
        
        for project in projects:
            # Get stamps for this project
            stamps_query = Stamp.objects.filter(project_id=project.id)
            
            if start_date_obj:
                stamps_query = stamps_query.filter(date__gte=start_date_obj)
            if end_date_obj:
                stamps_query = stamps_query.filter(date__lte=end_date_obj)
            
            stamps = stamps_query.select_related('user', 'task')
            
            # Calculate total hours
            total_minutes = 0
            for stamp in stamps:
                total_minutes += parse_duration_to_minutes(stamp.duration)
            
            total_hours = total_minutes // 60
            remaining_minutes = total_minutes % 60
            
            # Get unique employees
            unique_employees = stamps.values(
                'user_id', 
                'user__firstname', 
                'user__lastname', 
                'user__email'
            ).distinct()
            
            # Calculate hours per employee
            employee_hours = []
            for emp in unique_employees:
                emp_stamps = stamps.filter(user_id=emp['user_id'])
                emp_minutes = 0
                for stamp in emp_stamps:
                    emp_minutes += parse_duration_to_minutes(stamp.duration)
                
                emp_hours = emp_minutes // 60
                emp_remaining_minutes = emp_minutes % 60
                
                employee_hours.append({
                    'id': str(emp['user_id']),
                    'name': f"{emp['user__firstname']} {emp['user__lastname']}",
                    'email': emp['user__email'],
                    'total_hours': emp_hours,
                    'total_minutes': emp_remaining_minutes,
                    'total_hours_formatted': f"{emp_hours}:{emp_remaining_minutes:02d}",
                    'stamp_count': emp_stamps.count()
                })
            
            # Get task details with hours
            task_details = []
            tasks = Task.objects.filter(project_id=project.id)
            
            for task in tasks:
                task_stamps = stamps.filter(task_id=task.id)
                task_minutes = 0
                for stamp in task_stamps:
                    task_minutes += parse_duration_to_minutes(stamp.duration)
                
                task_hours = task_minutes // 60
                task_remaining_minutes = task_minutes % 60
                
                task_details.append({
                    'id': str(task.id),
                    'name': task.name,
                    'code': task.code,
                    'description': task.description,
                    'estimated_time': task.estimated_time,
                    'total_hours': task_hours,
                    'total_minutes': task_remaining_minutes,
                    'total_hours_formatted': f"{task_hours}:{task_remaining_minutes:02d}",
                    'stamp_count': task_stamps.count()
                })
            
            # Get client information
            client_info = None
            if project.customer:
                client_info = {
                    'id': str(project.customer.id),
                    'name': project.customer.name,
                    'contact_email': project.customer.contact_email,
                    'contact_phone': project.customer.contact_phone
                }
            elif project.client:
                # Fallback to client field if customer is not set
                client_info = {
                    'name': project.client
                }
            
            project_reports.append({
                'project': {
                    'id': str(project.id),
                    'name': project.name,
                    'code': project.code,
                    'description': project.description,
                    'status': project.status,
                    'start_date': project.start_date.strftime('%Y-%m-%d') if project.start_date else None,
                    'end_date': project.end_date.strftime('%Y-%m-%d') if project.end_date else None,
                    'due_date': project.due_date.strftime('%Y-%m-%d') if project.due_date else None,
                    'estimated_time': project.estimated_time,
                    'client': client_info
                },
                'summary': {
                    'total_hours': total_hours,
                    'total_minutes': remaining_minutes,
                    'total_hours_formatted': f"{total_hours}:{remaining_minutes:02d}",
                    'total_stamps': stamps.count(),
                    'total_tasks': tasks.count(),
                    'unique_employees_count': unique_employees.count()
                },
                'tasks': task_details,
                'employees': employee_hours
            })
        
        return Response({
            'reports': project_reports,
            'filters': {
                'project_id': project_id,
                'start_date': start_date,
                'end_date': end_date
            }
        })
    except Exception as e:
        log_error('project_report', e)
        return Response(
            {"error": "An error occurred while generating project report"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )


@api_view(['GET'])
@authentication_classes([])
@permission_classes([AllowAny])
def project_report_excel(request):
    """
    Generate project report as Excel file
    Query params: project_id, start_date, end_date
    """
    try:
        project_id = request.query_params.get('project_id')
        start_date = request.query_params.get('start_date')
        end_date = request.query_params.get('end_date')
        
        # Parse date filters
        start_date_obj = None
        end_date_obj = None
        if start_date:
            try:
                start_date_obj = datetime.strptime(start_date, '%Y-%m-%d').date()
            except ValueError:
                pass
        if end_date:
            try:
                end_date_obj = datetime.strptime(end_date, '%Y-%m-%d').date()
            except ValueError:
                pass
        
        # Get projects
        if project_id:
            projects = Project.objects.filter(id=project_id)
        else:
            projects = Project.objects.all()
        
        # Create Excel workbook
        wb = Workbook()
        ws = wb.active
        ws.title = "Project Report"
        
        # Header style
        header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
        header_font = Font(bold=True, color="FFFFFF", size=12)
        border = Border(
            left=Side(style='thin'),
            right=Side(style='thin'),
            top=Side(style='thin'),
            bottom=Side(style='thin')
        )
        
        # Title
        ws.merge_cells('A1:F1')
        title_cell = ws['A1']
        title_cell.value = "Project Report"
        title_cell.font = Font(bold=True, size=16)
        title_cell.alignment = Alignment(horizontal='center', vertical='center')
        
        row = 3
        if start_date or end_date:
            ws[f'A{row}'] = f"Date Range: {start_date or 'N/A'} to {end_date or 'N/A'}"
            row += 1
        
        row += 1
        
        # Process each project
        for project in projects:
            # Project header
            ws.merge_cells(f'A{row}:F{row}')
            project_header = ws[f'A{row}']
            project_header.value = f"Project: {project.name} ({project.code or 'N/A'})"
            project_header.font = Font(bold=True, size=14)
            project_header.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
            row += 1
            
            # Get stamps for this project
            stamps_query = Stamp.objects.filter(project_id=project.id)
            
            if start_date_obj:
                stamps_query = stamps_query.filter(date__gte=start_date_obj)
            if end_date_obj:
                stamps_query = stamps_query.filter(date__lte=end_date_obj)
            
            stamps = stamps_query.select_related('user', 'task')
            
            # Calculate summary
            total_minutes = 0
            for stamp in stamps:
                total_minutes += parse_duration_to_minutes(stamp.duration)
            
            total_hours = total_minutes // 60
            remaining_minutes = total_minutes % 60
            tasks = Task.objects.filter(project_id=project.id)
            
            # Summary row
            ws.cell(row=row, column=1).value = "Summary"
            ws.cell(row=row, column=1).font = Font(bold=True)
            ws.cell(row=row, column=2).value = f"Total Hours: {total_hours}:{remaining_minutes:02d}"
            ws.cell(row=row, column=3).value = f"Total Stamps: {stamps.count()}"
            ws.cell(row=row, column=4).value = f"Total Tasks: {tasks.count()}"
            row += 2
            
            # Tasks table headers
            headers = ['Task Name', 'Code', 'Estimated', 'Actual Hours', 'Stamps']
            for col, header in enumerate(headers, 1):
                cell = ws.cell(row=row, column=col)
                cell.value = header
                cell.fill = header_fill
                cell.font = header_font
                cell.border = border
                cell.alignment = Alignment(horizontal='center', vertical='center')
            row += 1
            
            # Tasks data
            for task in tasks:
                task_stamps = stamps.filter(task_id=task.id)
                task_minutes = 0
                for stamp in task_stamps:
                    task_minutes += parse_duration_to_minutes(stamp.duration)
                
                task_hours = task_minutes // 60
                task_remaining_minutes = task_minutes % 60
                
                ws.cell(row=row, column=1).value = task.name
                ws.cell(row=row, column=2).value = task.code or 'N/A'
                ws.cell(row=row, column=3).value = task.estimated_time or 'N/A'
                ws.cell(row=row, column=4).value = f"{task_hours}:{task_remaining_minutes:02d}"
                ws.cell(row=row, column=5).value = task_stamps.count()
                
                for col in range(1, 6):
                    ws.cell(row=row, column=col).border = border
                
                row += 1
            
            row += 1
            
            # Employees table headers
            headers = ['Employee Name', 'Email', 'Total Hours', 'Stamps']
            for col, header in enumerate(headers, 1):
                cell = ws.cell(row=row, column=col)
                cell.value = header
                cell.fill = header_fill
                cell.font = header_font
                cell.border = border
                cell.alignment = Alignment(horizontal='center', vertical='center')
            row += 1
            
            # Employees data
            unique_employees = stamps.values(
                'user_id', 
                'user__firstname', 
                'user__lastname', 
                'user__email'
            ).distinct()
            
            for emp in unique_employees:
                emp_stamps = stamps.filter(user_id=emp['user_id'])
                emp_minutes = 0
                for stamp in emp_stamps:
                    emp_minutes += parse_duration_to_minutes(stamp.duration)
                
                emp_hours = emp_minutes // 60
                emp_remaining_minutes = emp_minutes % 60
                emp_name = f"{emp['user__firstname']} {emp['user__lastname']}".strip()
                
                ws.cell(row=row, column=1).value = emp_name or emp['user__email']
                ws.cell(row=row, column=2).value = emp['user__email']
                ws.cell(row=row, column=3).value = f"{emp_hours}:{emp_remaining_minutes:02d}"
                ws.cell(row=row, column=4).value = emp_stamps.count()
                
                for col in range(1, 5):
                    ws.cell(row=row, column=col).border = border
                
                row += 1
            
            row += 2  # Space between projects
        
        # Auto-adjust column widths
        for col in range(1, 6):
            max_length = 0
            column = get_column_letter(col)
            for cell in ws[column]:
                try:
                    if len(str(cell.value)) > max_length:
                        max_length = len(str(cell.value))
                except:
                    pass
            adjusted_width = min(max_length + 2, 50)
            ws.column_dimensions[column].width = adjusted_width
        
        # Create response
        response = HttpResponse(
            content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )
        filename = f"project_report_{start_date or 'all'}_{end_date or 'all'}.xlsx"
        response['Content-Disposition'] = f'attachment; filename="{filename}"'
        
        wb.save(response)
        return response
        
    except Exception as e:
        log_error('project_report_excel', e)
        return Response(
            {"error": "An error occurred while generating Excel report"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )


@api_view(['GET'])
@authentication_classes([])
@permission_classes([AllowAny])
def project_report_pdf(request):
    """
    Generate project report as PDF file
    Query params: project_id, start_date, end_date
    """
    try:
        project_id = request.query_params.get('project_id')
        start_date = request.query_params.get('start_date')
        end_date = request.query_params.get('end_date')
        
        # Parse date filters
        start_date_obj = None
        end_date_obj = None
        if start_date:
            try:
                start_date_obj = datetime.strptime(start_date, '%Y-%m-%d').date()
            except ValueError:
                pass
        if end_date:
            try:
                end_date_obj = datetime.strptime(end_date, '%Y-%m-%d').date()
            except ValueError:
                pass
        
        # Get projects
        if project_id:
            projects = Project.objects.filter(id=project_id)
        else:
            projects = Project.objects.all()
        
        # Create PDF
        buffer = io.BytesIO()
        doc = SimpleDocTemplate(buffer, pagesize=A4, topMargin=0.5*inch, bottomMargin=0.5*inch)
        elements = []
        
        styles = getSampleStyleSheet()
        title_style = ParagraphStyle(
            'CustomTitle',
            parent=styles['Heading1'],
            fontSize=18,
            textColor=colors.HexColor('#366092'),
            spaceAfter=30,
            alignment=1
        )
        
        # Title
        title = Paragraph("Project Report", title_style)
        elements.append(title)
        elements.append(Spacer(1, 0.2*inch))
        
        # Filters info
        if start_date or end_date:
            filter_text = f"Date Range: {start_date or 'N/A'} to {end_date or 'N/A'}"
            elements.append(Paragraph(filter_text, styles['Normal']))
            elements.append(Spacer(1, 0.1*inch))
        
        # Process each project
        for project in projects:
            # Project header
            project_style = ParagraphStyle(
                'ProjectHeader',
                parent=styles['Heading2'],
                fontSize=14,
                textColor=colors.HexColor('#366092'),
                spaceAfter=10,
                spaceBefore=20
            )
            elements.append(Paragraph(f"Project: {project.name} ({project.code or 'N/A'})", project_style))
            
            # Get stamps for this project
            stamps_query = Stamp.objects.filter(project_id=project.id)
            
            if start_date_obj:
                stamps_query = stamps_query.filter(date__gte=start_date_obj)
            if end_date_obj:
                stamps_query = stamps_query.filter(date__lte=end_date_obj)
            
            stamps = stamps_query.select_related('user', 'task')
            
            # Calculate summary
            total_minutes = 0
            for stamp in stamps:
                total_minutes += parse_duration_to_minutes(stamp.duration)
            
            total_hours = total_minutes // 60
            remaining_minutes = total_minutes % 60
            tasks = Task.objects.filter(project_id=project.id)
            
            # Summary paragraph
            summary_text = f"Total Hours: {total_hours}:{remaining_minutes:02d} | Total Stamps: {stamps.count()} | Total Tasks: {tasks.count()}"
            elements.append(Paragraph(summary_text, styles['Normal']))
            elements.append(Spacer(1, 0.1*inch))
            
            # Tasks table
            table_data = [['Task Name', 'Code', 'Estimated', 'Actual Hours', 'Stamps']]
            
            for task in tasks:
                task_stamps = stamps.filter(task_id=task.id)
                task_minutes = 0
                for stamp in task_stamps:
                    task_minutes += parse_duration_to_minutes(stamp.duration)
                
                task_hours = task_minutes // 60
                task_remaining_minutes = task_minutes % 60
                
                table_data.append([
                    task.name,
                    task.code or 'N/A',
                    task.estimated_time or 'N/A',
                    f"{task_hours}:{task_remaining_minutes:02d}",
                    str(task_stamps.count())
                ])
            
            # Create tasks table
            table = Table(table_data, colWidths=[2*inch, 1*inch, 1*inch, 1*inch, 0.8*inch])
            table.setStyle(TableStyle([
                ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#366092')),
                ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
                ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                ('FONTSIZE', (0, 0), (-1, 0), 10),
                ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
                ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
                ('GRID', (0, 0), (-1, -1), 1, colors.grey),
                ('FONTSIZE', (0, 1), (-1, -1), 9),
            ]))
            
            elements.append(table)
            elements.append(Spacer(1, 0.2*inch))
            
            # Employees table
            employee_table_data = [['Employee Name', 'Email', 'Total Hours', 'Stamps']]
            
            unique_employees = stamps.values(
                'user_id', 
                'user__firstname', 
                'user__lastname', 
                'user__email'
            ).distinct()
            
            for emp in unique_employees:
                emp_stamps = stamps.filter(user_id=emp['user_id'])
                emp_minutes = 0
                for stamp in emp_stamps:
                    emp_minutes += parse_duration_to_minutes(stamp.duration)
                
                emp_hours = emp_minutes // 60
                emp_remaining_minutes = emp_minutes % 60
                emp_name = f"{emp['user__firstname']} {emp['user__lastname']}".strip()
                
                employee_table_data.append([
                    emp_name or emp['user__email'],
                    emp['user__email'],
                    f"{emp_hours}:{emp_remaining_minutes:02d}",
                    str(emp_stamps.count())
                ])
            
            # Create employees table
            emp_table = Table(employee_table_data, colWidths=[2*inch, 2*inch, 1*inch, 0.8*inch])
            emp_table.setStyle(TableStyle([
                ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#366092')),
                ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
                ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                ('FONTSIZE', (0, 0), (-1, 0), 10),
                ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
                ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
                ('GRID', (0, 0), (-1, -1), 1, colors.grey),
                ('FONTSIZE', (0, 1), (-1, -1), 9),
            ]))
            
            elements.append(emp_table)
            elements.append(PageBreak())
        
        # Build PDF
        doc.build(elements)
        
        # Create response
        response = HttpResponse(buffer.getvalue(), content_type='application/pdf')
        filename = f"project_report_{start_date or 'all'}_{end_date or 'all'}.pdf"
        response['Content-Disposition'] = f'attachment; filename="{filename}"'
        
        return response
        
    except Exception as e:
        log_error('project_report_pdf', e)
        return Response(
            {"error": "An error occurred while generating PDF report"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
