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, Q
from django.utils import timezone
from datetime import 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 Client
from .serializers import ClientSerializer
from projects.models import Project
from stamps.models import Stamp
from user.models import User
from ErrorLogs.utils import log_error

@api_view(['GET', 'POST'])
@permission_classes([AllowAny])
def client_list(request):
    if request.method == 'GET':
        try:
            clients = Client.objects.all()
            serializer = ClientSerializer(clients, many=True)
            return Response(serializer.data)
        except Exception as e:
            log_error('client_list.GET', e)
            return Response(
                {"error": "An error occurred while fetching clients"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    elif request.method == 'POST':
        try:
            with transaction.atomic():
                serializer = ClientSerializer(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('client_list.POST', e)
            return Response(
                {"error": "An error occurred while creating client"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

@api_view(['GET', 'PUT', 'DELETE'])
@permission_classes([AllowAny])
def client_detail(request, pk):
    try:
        client = Client.objects.get(pk=pk)
    except Client.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)
    except Exception as e:
        log_error('client_detail.get_client', e)
        return Response(
            {"error": "An error occurred while fetching client"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )

    if request.method == 'GET':
        try:
            serializer = ClientSerializer(client)
            return Response(serializer.data)
        except Exception as e:
            log_error('client_detail.GET', e)
            return Response(
                {"error": "An error occurred while fetching client details"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    elif request.method == 'PUT':
        try:
            with transaction.atomic():
                serializer = ClientSerializer(client, 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('client_detail.PUT', e)
            return Response(
                {"error": "An error occurred while updating client"},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    elif request.method == 'DELETE':
        try:
            with transaction.atomic():
                client.delete()
                return Response(status=status.HTTP_204_NO_CONTENT)
        except Exception as e:
            log_error('client_detail.DELETE', e)
            return Response(
                {"error": "An error occurred while deleting client"},
                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 client_report(request):
    """
    Generate client report with project details, hours, and employee information
    Query params: client_id (optional - if not provided, returns all clients)
    """
    try:
        client_id = request.query_params.get('client_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 clients
        if client_id:
            clients = Client.objects.filter(id=client_id)
        else:
            clients = Client.objects.all()
        
        client_reports = []
        
        for client in clients:
            # Get projects for this client - check both customer relationship and client field
            projects = Project.objects.filter(
                Q(customer__name=client.name) | Q(client=client.name)
            )
            
            # Get stamps for projects of this client
            project_ids = list(projects.values_list('id', flat=True))
            stamps_query = Stamp.objects.filter(project_id__in=project_ids)
            
            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', 'project', '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()
            
            # Get project details with hours
            project_details = []
            for project in projects:
                project_stamps = stamps.filter(project_id=project.id)
                project_minutes = 0
                for stamp in project_stamps:
                    project_minutes += parse_duration_to_minutes(stamp.duration)
                
                project_hours = project_minutes // 60
                project_remaining_minutes = project_minutes % 60
                
                project_details.append({
                    'id': str(project.id),
                    'name': project.name,
                    'code': project.code,
                    'status': project.status,
                    'total_hours': project_hours,
                    'total_minutes': project_remaining_minutes,
                    'total_hours_formatted': f"{project_hours}:{project_remaining_minutes:02d}",
                    'stamp_count': project_stamps.count()
                })
            
            client_reports.append({
                'client': {
                    'id': str(client.id),
                    'name': client.name,
                    'description': client.description,
                    'contact_email': client.contact_email,
                    'contact_phone': client.contact_phone,
                    'address': client.address
                },
                'summary': {
                    'total_projects': projects.count(),
                    'total_hours': total_hours,
                    'total_minutes': remaining_minutes,
                    'total_hours_formatted': f"{total_hours}:{remaining_minutes:02d}",
                    'total_stamps': stamps.count(),
                    'unique_employees_count': unique_employees.count()
                },
                'projects': project_details,
                'employees': [
                    {
                        'id': str(emp['user_id']),
                        'name': f"{emp['user__firstname']} {emp['user__lastname']}",
                        'email': emp['user__email']
                    }
                    for emp in unique_employees
                ]
            })
        
        return Response({
            'reports': client_reports,
            'filters': {
                'client_id': client_id,
                'start_date': start_date,
                'end_date': end_date
            }
        })
    except Exception as e:
        log_error('client_report', e)
        return Response(
            {"error": "An error occurred while generating client report"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )


@api_view(['GET'])
@authentication_classes([])
@permission_classes([AllowAny])
def client_report_excel(request):
    """
    Generate client report as Excel file
    Query params: client_id, start_date, end_date
    """
    try:
        client_id = request.query_params.get('client_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 clients
        if client_id:
            clients = Client.objects.filter(id=client_id)
        else:
            clients = Client.objects.all()
        
        # Create Excel workbook
        wb = Workbook()
        ws = wb.active
        ws.title = "Client 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 = "Client 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 client
        for client in clients:
            # Client header
            ws.merge_cells(f'A{row}:F{row}')
            client_header = ws[f'A{row}']
            client_header.value = f"Client: {client.name}"
            client_header.font = Font(bold=True, size=14)
            client_header.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
            row += 1
            
            # Get projects for this client
            projects = Project.objects.filter(
                Q(customer__name=client.name) | Q(client=client.name)
            )
            
            # Get stamps for projects of this client
            project_ids = list(projects.values_list('id', flat=True))
            stamps_query = Stamp.objects.filter(project_id__in=project_ids)
            
            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', 'project', 'task')
            
            # Summary row
            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
            
            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 Projects: {projects.count()}"
            ws.cell(row=row, column=3).value = f"Total Hours: {total_hours}:{remaining_minutes:02d}"
            ws.cell(row=row, column=4).value = f"Total Stamps: {stamps.count()}"
            row += 2
            
            # Projects table headers
            headers = ['Project Name', 'Code', 'Status', '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
            
            # Projects data
            for project in projects:
                project_stamps = stamps.filter(project_id=project.id)
                project_minutes = 0
                for stamp in project_stamps:
                    project_minutes += parse_duration_to_minutes(stamp.duration)
                
                project_hours = project_minutes // 60
                project_remaining_minutes = project_minutes % 60
                
                ws.cell(row=row, column=1).value = project.name
                ws.cell(row=row, column=2).value = project.code or 'N/A'
                ws.cell(row=row, column=3).value = project.status
                ws.cell(row=row, column=4).value = f"{project_hours}:{project_remaining_minutes:02d}"
                ws.cell(row=row, column=5).value = project_stamps.count()
                
                for col in range(1, 6):
                    ws.cell(row=row, column=col).border = border
                
                row += 1
            
            row += 2  # Space between clients
        
        # 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"client_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('client_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 client_report_pdf(request):
    """
    Generate client report as PDF file
    Query params: client_id, start_date, end_date
    """
    try:
        client_id = request.query_params.get('client_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 clients
        if client_id:
            clients = Client.objects.filter(id=client_id)
        else:
            clients = Client.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("Client 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 client
        for client in clients:
            # Client header
            client_style = ParagraphStyle(
                'ClientHeader',
                parent=styles['Heading2'],
                fontSize=14,
                textColor=colors.HexColor('#366092'),
                spaceAfter=10,
                spaceBefore=20
            )
            elements.append(Paragraph(f"Client: {client.name}", client_style))
            
            # Get projects for this client
            projects = Project.objects.filter(
                Q(customer__name=client.name) | Q(client=client.name)
            )
            
            # Get stamps for projects of this client
            project_ids = list(projects.values_list('id', flat=True))
            stamps_query = Stamp.objects.filter(project_id__in=project_ids)
            
            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', 'project', '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
            
            # Summary paragraph
            summary_text = f"Total Projects: {projects.count()} | Total Hours: {total_hours}:{remaining_minutes:02d} | Total Stamps: {stamps.count()}"
            elements.append(Paragraph(summary_text, styles['Normal']))
            elements.append(Spacer(1, 0.1*inch))
            
            # Projects table
            table_data = [['Project Name', 'Code', 'Status', 'Total Hours', 'Stamps']]
            
            for project in projects:
                project_stamps = stamps.filter(project_id=project.id)
                project_minutes = 0
                for stamp in project_stamps:
                    project_minutes += parse_duration_to_minutes(stamp.duration)
                
                project_hours = project_minutes // 60
                project_remaining_minutes = project_minutes % 60
                
                table_data.append([
                    project.name,
                    project.code or 'N/A',
                    project.status,
                    f"{project_hours}:{project_remaining_minutes:02d}",
                    str(project_stamps.count())
                ])
            
            # Create 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(PageBreak())
        
        # Build PDF
        doc.build(elements)
        
        # Create response
        response = HttpResponse(buffer.getvalue(), content_type='application/pdf')
        filename = f"client_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('client_report_pdf', e)
        return Response(
            {"error": "An error occurred while generating PDF report"},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )

