from decimal import Decimal
from rest_framework import status, permissions
from rest_framework.views import APIView
from .models import CostSheet, CostSheetMember, CostSheetTool
from .serializers import (
    CostSheetListSerializer, CostSheetDetailSerializer,
    CostSheetMemberSerializer, CostSheetToolSerializer
)
from apps.leads.models import Lead, LeadActivity
from apps.users.models import User
from apps.users.permissions import IsManagement
from apps.users.views import api_response


class CostSheetListView(APIView):
    """List all cost sheets or create one for a lead."""
    permission_classes = [permissions.IsAuthenticated, IsManagement]

    def get(self, request):
        lead_id = request.query_params.get('lead')
        sheets = CostSheet.objects.select_related('lead', 'created_by').all()
        if lead_id:
            sheets = sheets.filter(lead_id=lead_id)
        serializer = CostSheetListSerializer(sheets, many=True)
        return api_response(data=serializer.data)

    def post(self, request):
        """Create a new cost sheet for a lead (PM initiates)."""
        lead_id = request.data.get('lead')
        if not lead_id:
            return api_response(message='Lead ID required', status_code=status.HTTP_400_BAD_REQUEST)

        try:
            lead = Lead.objects.get(pk=lead_id)
        except Lead.DoesNotExist:
            return api_response(message='Lead not found', status_code=status.HTTP_404_NOT_FOUND)

        # Get next version
        last_version = CostSheet.objects.filter(lead=lead).order_by('-version').first()
        next_version = (last_version.version + 1) if last_version else 1

        sheet = CostSheet.objects.create(
            lead=lead,
            version=next_version,
            client_budget=lead.proposed_budget or 0,
            created_by=request.user,
            overhead_value=Decimal(request.data.get('overhead_value', '10')),
            overhead_type=request.data.get('overhead_type', 'percent'),
            contingency_percent=Decimal(request.data.get('contingency_percent', '5')),
            profit_percent=Decimal(request.data.get('profit_percent', '20')),
            notes=request.data.get('notes', ''),
        )

        # Update lead status
        if lead.status in ('Client_Meeting', 'Internal_Review', 'Qualified', 'Requirements_Submitted'):
            lead.status = 'Costing_In_Progress'
            lead.save()
            LeadActivity.objects.create(
                lead=lead, actor=request.user,
                action='Costing Initiated',
                details=f'Cost sheet v{next_version} created'
            )

        serializer = CostSheetDetailSerializer(sheet)
        return api_response(data=serializer.data, message='Cost sheet created', status_code=status.HTTP_201_CREATED)


class CostSheetDetailView(APIView):
    """Get, update, or recalculate a cost sheet."""
    permission_classes = [permissions.IsAuthenticated, IsManagement]

    def get(self, request, pk):
        try:
            sheet = CostSheet.objects.prefetch_related(
                'team_members__user', 'tool_items'
            ).select_related('lead', 'created_by').get(pk=pk)
        except CostSheet.DoesNotExist:
            return api_response(message='Cost sheet not found', status_code=status.HTTP_404_NOT_FOUND)

        serializer = CostSheetDetailSerializer(sheet)
        return api_response(data=serializer.data)

    def patch(self, request, pk):
        try:
            sheet = CostSheet.objects.get(pk=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='Cannot edit a submitted cost sheet', status_code=status.HTTP_400_BAD_REQUEST)

        # Update editable fields
        for field in ['overhead_type', 'overhead_value', 'contingency_percent', 'profit_percent', 'notes']:
            if field in request.data:
                val = request.data[field]
                if field in ('overhead_value', 'contingency_percent', 'profit_percent'):
                    val = Decimal(str(val))
                setattr(sheet, field, val)

        sheet.save()
        sheet.calculate_totals()

        serializer = CostSheetDetailSerializer(sheet)
        return api_response(data=serializer.data, message='Cost sheet updated')


class CostSheetRecalculateView(APIView):
    """Force recalculation of totals."""
    permission_classes = [permissions.IsAuthenticated, IsManagement]

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

        sheet.calculate_totals()
        serializer = CostSheetDetailSerializer(sheet)
        return api_response(data=serializer.data, message='Totals recalculated')


class CostSheetMemberView(APIView):
    """Add or remove team members from a cost sheet."""
    permission_classes = [permissions.IsAuthenticated, IsManagement]

    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='Cannot edit a submitted cost sheet', status_code=status.HTTP_400_BAD_REQUEST)

        user_id = request.data.get('user')
        try:
            user = User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return api_response(message='User not found', status_code=status.HTTP_404_NOT_FOUND)

        member, created = CostSheetMember.objects.update_or_create(
            cost_sheet=sheet, user=user,
            defaults={
                'project_role': request.data.get('project_role', user.roles.first().name if user.roles.exists() else 'Member'),
                'hourly_rate': user.hourly_rate,
                'estimated_hours': Decimal(str(request.data.get('estimated_hours', 0))),
            }
        )

        # Recalculate
        sheet.calculate_totals()

        serializer = CostSheetDetailSerializer(sheet)
        return api_response(
            data=serializer.data,
            message=f'{"Added" if created else "Updated"} {user.full_name}',
            status_code=status.HTTP_201_CREATED if created else status.HTTP_200_OK
        )

    def delete(self, request, sheet_pk):
        member_id = request.data.get('member_id')
        try:
            sheet = CostSheet.objects.get(pk=sheet_pk)
            member = CostSheetMember.objects.get(pk=member_id, cost_sheet=sheet)
        except (CostSheet.DoesNotExist, CostSheetMember.DoesNotExist):
            return api_response(message='Not found', status_code=status.HTTP_404_NOT_FOUND)

        name = member.user.full_name
        member.delete()
        sheet.calculate_totals()

        serializer = CostSheetDetailSerializer(sheet)
        return api_response(data=serializer.data, message=f'Removed {name}')


class CostSheetToolView(APIView):
    """Add, update, or remove tool/license items."""
    permission_classes = [permissions.IsAuthenticated, IsManagement]

    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='Cannot edit a submitted cost sheet', status_code=status.HTTP_400_BAD_REQUEST)

        tool = CostSheetTool.objects.create(
            cost_sheet=sheet,
            name=request.data.get('name', ''),
            purpose=request.data.get('purpose', ''),
            cost=Decimal(str(request.data.get('cost', 0))),
        )

        sheet.calculate_totals()

        serializer = CostSheetDetailSerializer(sheet)
        return api_response(data=serializer.data, message='Tool added', status_code=status.HTTP_201_CREATED)

    def delete(self, request, sheet_pk):
        tool_id = request.data.get('tool_id')
        try:
            sheet = CostSheet.objects.get(pk=sheet_pk)
            tool = CostSheetTool.objects.get(pk=tool_id, cost_sheet=sheet)
        except (CostSheet.DoesNotExist, CostSheetTool.DoesNotExist):
            return api_response(message='Not found', status_code=status.HTTP_404_NOT_FOUND)

        tool.delete()
        sheet.calculate_totals()

        serializer = CostSheetDetailSerializer(sheet)
        return api_response(data=serializer.data, message='Tool removed')
