from django.utils import timezone
from rest_framework import status, permissions
from rest_framework.views import APIView
from .models import ApprovalFlow, ApprovalAction
from .serializers import ApprovalFlowSerializer, ApprovalActionSerializer
from apps.costing.models import CostSheet
from apps.leads.models import Lead, LeadActivity
from apps.users.views import api_response


class ApprovalListView(APIView):
    """List approval flows — filtered by role."""
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        user = request.user
        flows = ApprovalFlow.objects.select_related(
            'cost_sheet', 'lead', 'submitted_by'
        ).prefetch_related('actions__actor').all()

        # Filter by what the user can review
        stage_filter = request.query_params.get('stage')
        status_filter = request.query_params.get('status')

        if stage_filter:
            flows = flows.filter(current_stage=stage_filter)
        if status_filter:
            flows = flows.filter(overall_status=status_filter)

        # Role-based filtering: show only what needs their action
        if request.query_params.get('my_queue') == 'true':
            q_filter = models.Q()
            if user.has_role('TL'):
                q_filter |= models.Q(current_stage='TL_Review')
            if user.has_role('PM'):
                q_filter |= models.Q(current_stage='PM_Review')
            if user.has_role('CEO'):
                q_filter |= models.Q(current_stage='CEO_Decision')
            
            if q_filter:
                flows = flows.filter(q_filter, overall_status='Pending')
            else:
                flows = flows.none()

        serializer = ApprovalFlowSerializer(flows, many=True)
        return api_response(data=serializer.data)


class ApprovalDetailView(APIView):
    """Get approval flow details."""
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, pk):
        try:
            flow = ApprovalFlow.objects.select_related(
                'cost_sheet', 'lead', 'submitted_by'
            ).prefetch_related('actions__actor').get(pk=pk)
        except ApprovalFlow.DoesNotExist:
            return api_response(message='Approval not found', status_code=status.HTTP_404_NOT_FOUND)

        serializer = ApprovalFlowSerializer(flow)
        return api_response(data=serializer.data)


class SubmitForApprovalView(APIView):
    """PM submits a cost sheet for the approval pipeline."""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, sheet_pk):
        try:
            sheet = CostSheet.objects.get(pk=sheet_pk)
        except CostSheet.DoesNotExist:
            return api_response(message='Cost sheet not found', status_code=status.HTTP_404_NOT_FOUND)

        if sheet.status not in ('Draft', 'Revised'):
            return api_response(
                message='Only draft or revised cost sheets can be submitted',
                status_code=status.HTTP_400_BAD_REQUEST
            )

        # Ensure there are team members
        if sheet.team_members.count() == 0:
            return api_response(
                message='Add at least one team member before submitting',
                status_code=status.HTTP_400_BAD_REQUEST
            )

        # Recalculate before submitting
        sheet.calculate_totals()
        sheet.status = 'Submitted'
        sheet.save()

        # Create or reset approval flow
        flow, created = ApprovalFlow.objects.update_or_create(
            cost_sheet=sheet,
            defaults={
                'lead': sheet.lead,
                'current_stage': 'TL_Review',
                'overall_status': 'Pending',
                'submitted_by': request.user,
            }
        )

        # Update lead status
        sheet.lead.status = 'Pending_Approval'
        sheet.lead.save()

        LeadActivity.objects.create(
            lead=sheet.lead, actor=request.user,
            action='Submitted for Approval',
            details=f'Cost sheet v{sheet.version} submitted — Total: PKR {sheet.total_cost:,.0f}'
        )

        serializer = ApprovalFlowSerializer(flow)
        return api_response(data=serializer.data, message='Submitted for approval')


class ApprovalActionView(APIView):
    """Take approval action: approve, reject, or revise."""
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, pk):
        try:
            flow = ApprovalFlow.objects.select_related('cost_sheet', 'lead').get(pk=pk)
        except ApprovalFlow.DoesNotExist:
            return api_response(message='Approval not found', status_code=status.HTTP_404_NOT_FOUND)

        if flow.overall_status != 'Pending':
            return api_response(message='This approval is no longer pending', status_code=status.HTTP_400_BAD_REQUEST)

        action = request.data.get('action')  # approve, reject, revise
        comment = request.data.get('comment', '').strip()

        if action not in ('approve', 'reject', 'revise'):
            return api_response(message='Invalid action', status_code=status.HTTP_400_BAD_REQUEST)
        if not comment:
            return api_response(message='Comment is mandatory', status_code=status.HTTP_400_BAD_REQUEST)

        user = request.user

        # Validate the user can act on the current stage
        stage_roles = {
            'TL_Review': ['TL', 'CEO'],
            'PM_Review': ['PM', 'CEO'],
            'CEO_Decision': ['CEO'],
        }
        allowed_roles = stage_roles.get(flow.current_stage, [])
        if not user.has_role(*allowed_roles):
            return api_response(
                message=f'Only {", ".join(allowed_roles)} can act on this stage',
                status_code=status.HTTP_403_FORBIDDEN
            )

        from django.db import transaction

        try:
            with transaction.atomic():
                # Record the action
                ApprovalAction.objects.create(
                    approval=flow,
                    stage=flow.current_stage,
                    actor=user,
                    action=action,
                    comment=comment
                )

                if action == 'approve':
                    # Try to advance to next stage
                    if flow.current_stage == 'CEO_Decision':
                        # Final approval!
                        flow.overall_status = 'Approved'
                        flow.completed_at = timezone.now()
                        flow.save()

                        flow.cost_sheet.status = 'Approved'
                        flow.cost_sheet.save()

                        flow.lead.status = 'Approved'
                        flow.lead.save()

                        # Automatically create a Project based on the Lead and Cost Sheet
                        from apps.projects.models import Project, ProjectMember
                        project = Project.objects.create(
                            lead=flow.lead,
                            name=flow.lead.title,
                            client_name=flow.lead.client_name,
                            service_type=flow.lead.service_type,
                            approved_budget=flow.cost_sheet.total_cost,
                            estimated_cost=flow.cost_sheet.total_cost,
                            status='Kickoff',
                            stage='Kickoff',
                            pm=flow.submitted_by  # Typically the PM who submitted it
                        )

                        # Transfer team members from Cost Sheet to Project
                        for member in flow.cost_sheet.team_members.all():
                            ProjectMember.objects.create(
                                project=project,
                                user=member.user,
                                role_on_project=member.project_role,
                                hourly_rate_snapshot=member.hourly_rate
                            )

                        LeadActivity.objects.create(
                            lead=flow.lead, actor=user,
                            action='CEO Approved',
                            details=f'Project created successfully — Budget: PKR {flow.cost_sheet.total_cost:,.0f}'
                        )
                    else:
                        flow.advance_stage()

                        stage_labels = {
                            'TL_Review': 'TL Review',
                            'PM_Review': 'PM Review',
                            'CEO_Decision': 'CEO Decision'
                        }
                        LeadActivity.objects.create(
                            lead=flow.lead, actor=user,
                            action=f'{stage_labels.get(flow.current_stage, flow.current_stage)} — Approved',
                            details=comment
                        )

                elif action == 'reject':
                    flow.overall_status = 'Rejected'
                    flow.completed_at = timezone.now()
                    flow.save()

                    flow.cost_sheet.status = 'Rejected'
                    flow.cost_sheet.save()

                    flow.lead.status = 'Rejected'
                    flow.lead.save()

                    LeadActivity.objects.create(
                        lead=flow.lead, actor=user,
                        action='Rejected',
                        details=f'Rejected at {flow.current_stage}: {comment}'
                    )

                elif action == 'revise':
                    flow.overall_status = 'Revised'
                    flow.save()

                    flow.cost_sheet.status = 'Revised'
                    flow.cost_sheet.save()

                    flow.lead.status = 'Costing_In_Progress'
                    flow.lead.save()

                    LeadActivity.objects.create(
                        lead=flow.lead, actor=user,
                        action='Sent for Revision',
                        details=f'Revise requested at {flow.current_stage}: {comment}'
                    )

        except Exception as e:
            return api_response(message=str(e), status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)

        serializer = ApprovalFlowSerializer(flow)
        return api_response(data=serializer.data, message=f'Action recorded: {action}')
