import csv
from django.http import HttpResponse
from rest_framework.views import APIView
from rest_framework import permissions
from django.db import models
from django.db.models import Count, Sum, Avg, F
from django.utils import timezone
from datetime import timedelta

# Import models from other apps
from apps.leads.models import Lead
from apps.projects.models import Project
from apps.tasks.models import Task, TimeLog
from apps.finance.models import Invoice, Expense
from apps.users.models import User
from apps.users.views import api_response


class ReportBaseView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get_date_bounds(self):
        start = self.request.query_params.get('start_date')
        end = self.request.query_params.get('end_date')
        return start, end

    def apply_date_filter(self, queryset, date_field):
        start, end = self.get_date_bounds()
        if start:
            queryset = queryset.filter(**{f"{date_field}__gte": start})
        if end:
            queryset = queryset.filter(**{f"{date_field}__lte": end})
        return queryset


class SalesReportView(ReportBaseView):
    def get(self, request):
        if not request.user.has_role('CEO', 'BD'):
            return api_response(status_code=403, message="Unauthorized")

        leads = self.apply_date_filter(Lead.objects.all(), 'created_at')
        if request.user.has_role('BD') and not request.user.has_role('CEO'):
            leads = leads.filter(created_by=request.user)

        total_leads = leads.count()
        won_leads = leads.filter(status='Approved')
        conversion_rate = (won_leads.count() / total_leads * 100) if total_leads > 0 else 0

        # Avg time to approval
        approval_times = []
        for l in won_leads:
            # Find the activity that marked it as Approved
            activity = l.activities.filter(action='Status Changed', details__icontains='to Approved').first()
            if activity:
                delta = activity.timestamp - l.created_at
                approval_times.append(delta.total_seconds() / 3600)  # hours
        
        avg_approval_hours = (sum(approval_times) / len(approval_times)) if approval_times else 0

        # Stage breakdown
        stages = leads.values('status').annotate(count=Count('id'))
        
        # Service breakdown
        services = leads.values('service_type').annotate(count=Count('id'))

        # BD Performance
        bd_perf = leads.values('created_by__full_name').annotate(
            total=Count('id'),
            won=Count('id', filter=models.Q(status='Approved'))
        )

        return api_response(data={
            'total_leads': total_leads,
            'conversion_rate': round(conversion_rate, 2),
            'avg_approval_hours': round(avg_approval_hours, 1),
            'stages': list(stages),
            'services': list(services),
            'bd_performance': list(bd_perf)
        })


class OperationsReportView(ReportBaseView):
    def get(self, request):
        if not request.user.has_role('CEO', 'PM', 'TL'):
            return api_response(status_code=403, message="Unauthorized")

        projects = self.apply_date_filter(Project.objects.all(), 'created_at')
        tasks = self.apply_date_filter(Task.objects.all(), 'created_at')

        total_projects = projects.count()
        active_projects = projects.filter(status='Active').count()
        
        # Task Completion Per Project
        projects_completion = []
        delivery_times = []
        for p in projects:
            p_tasks = tasks.filter(project=p)
            total_pt = p_tasks.count()
            done_pt = p_tasks.filter(status='Done').count()
            projects_completion.append({
                'name': p.name,
                'rate': round((done_pt/total_pt*100), 1) if total_pt > 0 else 0
            })
            if p.stage == 'Completed' and p.start_date:
                # Find completion date from logs
                log = p.stage_logs.filter(to_stage='Completed').first()
                if log:
                    delta = log.timestamp.date() - p.start_date
                    delivery_times.append(delta.days)

        avg_delivery_days = (sum(delivery_times) / len(delivery_times)) if delivery_times else 0

        # Overdue Tasks Alert
        overdue_tasks = tasks.filter(due_date__lt=timezone.now().date(), status__in=['Todo', 'In_Progress']).count()

        # Employee Utilization
        timelogs = TimeLog.objects.all()
        utilization = timelogs.values('user__full_name').annotate(total_hours=Sum('hours_logged'))

        return api_response(data={
            'total_projects': total_projects,
            'active_projects': active_projects,
            'projects_completion': projects_completion,
            'avg_delivery_days': round(avg_delivery_days, 1),
            'overdue_tasks': overdue_tasks,
            'utilization': list(utilization)
        })


class FinanceReportView(ReportBaseView):
    def get(self, request):
        if not request.user.has_role('CEO', 'Finance', 'PM'):
            return api_response(status_code=403, message="Unauthorized")

        projects = self.apply_date_filter(Project.objects.all(), 'created_at')
        invoices = self.apply_date_filter(Invoice.objects.all(), 'issue_date')
        expenses = self.apply_date_filter(Expense.objects.all(), 'date_incurred')

        # Limit to PM's projects if PM
        if request.user.has_role('PM') and not request.user.has_role('CEO', 'Finance'):
            projects = projects.filter(pm=request.user)
            invoices = invoices.filter(project__in=projects)
            expenses = expenses.filter(project__in=projects)

        # Totals
        total_billed = invoices.aggregate(Sum('total_amount'))['total_amount__sum'] or 0
        total_collected = invoices.aggregate(Sum('amount_paid'))['amount_paid__sum'] or 0
        total_expenses = expenses.aggregate(Sum('amount'))['amount__sum'] or 0

        # Monthly Trends (Basic aggregation)
        # Using __month and __year for grouping
        revenue_trend = invoices.filter(status='Paid').values('issue_date__year', 'issue_date__month').annotate(
            total=Sum('amount_paid')
        ).order_by('issue_date__year', 'issue_date__month')

        expense_trend = expenses.values('date_incurred__year', 'date_incurred__month').annotate(
            total=Sum('amount')
        ).order_by('date_incurred__year', 'date_incurred__month')

        # Invoice status breakdown
        inv_status = invoices.values('status').annotate(count=Count('id'), total=Sum('total_amount'))

        # Profitability & Over-budget Alerts
        profitability = []
        over_budget = []
        for p in projects:
            p_billed = p.invoices.aggregate(Sum('total_amount'))['total_amount__sum'] or 0
            p_expense = p.expenses.aggregate(Sum('amount'))['amount__sum'] or 0
            profitability.append({
                'project': p.name,
                'budget': p.approved_budget,
                'billed': p_billed,
                'expense': p_expense,
                'profit': p_billed - p_expense
            })
            if p.actual_cost > p.approved_budget:
                over_budget.append({
                    'name': p.name,
                    'actual': p.actual_cost,
                    'budget': p.approved_budget,
                    'diff': p.actual_cost - p.approved_budget
                })

        return api_response(data={
            'total_billed': total_billed,
            'total_collected': total_collected,
            'total_expenses': total_expenses,
            'net_profit': total_collected - total_expenses,
            'trends': {
                'revenue': list(revenue_trend),
                'expense': list(expense_trend)
            },
            'profitability': profitability,
            'over_budget': over_budget,
            'invoice_status_breakdown': list(inv_status)
        })




class HRReportView(ReportBaseView):
    def get(self, request):
        if not request.user.has_role('CEO', 'HR'):
            return api_response(status_code=403, message="Unauthorized")

        users = User.objects.filter(is_active=True)
        headcount = users.count()
        total_salary = users.aggregate(Sum('salary_pkr'))['salary_pkr__sum'] or 0

        dept_dist = users.values('department').annotate(count=Count('id'), salary=Sum('salary_pkr'))

        return api_response(data={
            'headcount': headcount,
            'monthly_salary_expense': total_salary,
            'department_metrics': list(dept_dist)
        })


class CombinedReportView(ReportBaseView):
    def get(self, request):
        if not (request.user.has_role('Finance') and request.user.has_role('HR')):
            if not request.user.has_role('CEO'):
                return api_response(status_code=403, message="Unauthorized")

        users = User.objects.filter(is_active=True)
        total_salary = users.aggregate(Sum('salary_pkr'))['salary_pkr__sum'] or 0

        invoices = self.apply_date_filter(Invoice.objects.all(), 'issue_date')
        total_collected = invoices.filter(status='Paid').aggregate(Sum('amount'))['amount__sum'] or 0

        cost_per_employee = (total_salary / users.count()) if users.count() > 0 else 0
        team_roi = (total_collected / total_salary) if total_salary > 0 else 0

        return api_response(data={
            'cost_per_employee': round(cost_per_employee, 2),
            'team_roi': round(team_roi, 2),
            'total_salary_expense': total_salary,
            'total_collected': total_collected
        })
class ExportReportView(ReportBaseView):
    """Generate CSV file for the requested report"""

    def get(self, request):
        report_type = request.query_params.get('type', 'sales')
        
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = f'attachment; filename="CyberArsenals_{report_type}_Report.csv"'
        writer = csv.writer(response)

        if report_type == 'sales':
            if not request.user.has_role('CEO', 'BD'):
                return api_response(status_code=403, message="Unauthorized")
            
            leads = self.apply_date_filter(Lead.objects.all(), 'created_at')
            writer.writerow(['Client Name', 'Title', 'Service Type', 'Status', 'Contract Type', 'Created Date'])
            for lead in leads:
                writer.writerow([lead.client_name, lead.title, lead.service_type, lead.status, lead.contract_type, lead.created_at.date()])

        elif report_type == 'finance':
            if not request.user.has_role('CEO', 'Finance', 'PM'):
                return api_response(status_code=403, message="Unauthorized")
                
            invoices = self.apply_date_filter(Invoice.objects.all(), 'issue_date')
            writer.writerow(['Invoice ID', 'Project', 'Total Amount', 'Amount Paid', 'Status', 'Issue Date', 'Due Date'])
            for inv in invoices:
                writer.writerow([inv.invoice_id, inv.project.name, inv.total_amount, inv.amount_paid, inv.status, inv.issue_date, inv.due_date])

        elif report_type == 'operations':
            if not request.user.has_role('CEO', 'PM', 'TL'):
                return api_response(status_code=403, message="Unauthorized")

            projects = self.apply_date_filter(Project.objects.all(), 'created_at')
            writer.writerow(['Project Name', 'Client', 'Status', 'Stage', 'PM', 'Budget', 'Actual Cost', 'Start Date'])
            for p in projects:
                writer.writerow([p.name, p.client_name, p.status, p.stage, p.pm.full_name if p.pm else 'N/A', p.approved_budget, p.actual_cost, p.start_date])

        return response
