from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from account.permissions import (
    HasTabPermission,
    user_can_see_all_shop_data,
    get_user_data_filter,
)
from rest_framework import status
from django.db.models import Sum, Count, Q
from django.utils import timezone
from datetime import datetime, timedelta
from shop_management.models.data.sale import Sale
from shop_management.models.data.sale_payment import SalePayment
from shop_management.models.data.sale_return import SaleReturn
from shop_management.models.data.customer_balance_payment import CustomerBalancePayment
from shop_management.serializers.data.sale import SaleSerializer
from shop_management.serializers.data.sale_payment import SalePaymentSerializer
from shop_management.serializers.data.sale_return import SaleReturnSerializer
from shop_management.serializers.data.customer_balance_payment import CustomerBalancePaymentSerializer
from shop_management.services.reporting import reportable_sale_filter, reportable_sales

@api_view(['GET'])
@permission_classes([IsAuthenticated, HasTabPermission])
def comprehensive_sale_report(request):
    try:
        # Get date filters
        start_date = request.GET.get('start_date')
        end_date = request.GET.get('end_date')
        
        # Base querysets (scope by owner unless user has reports tab and can see all)
        if user_can_see_all_shop_data(request.user, "reports"):
            sales_qs = Sale.objects.all()
            payments_qs = SalePayment.objects.all()
            returns_qs = SaleReturn.objects.all()
            balance_payments_qs = CustomerBalancePayment.objects.filter(is_void=False)
        else:
            sales_qs = Sale.objects.filter(get_user_data_filter(request.user, "shop")).distinct()
            payments_qs = SalePayment.objects.filter(get_user_data_filter(request.user, "sale__shop")).distinct()
            returns_qs = SaleReturn.objects.filter(get_user_data_filter(request.user, "shop")).distinct()
            balance_payments_qs = CustomerBalancePayment.objects.filter(is_void=False).filter(get_user_data_filter(request.user, "customer__shop")).distinct()

        # Cancelled/draft invoices remain in sales history, never financial reports.
        sales_qs = reportable_sales(sales_qs)
        payments_qs = payments_qs.filter(reportable_sale_filter("sale__"))
        returns_qs = returns_qs.filter(reportable_sale_filter("sale__"))

        # Apply date filters
        if start_date:
            start_date = datetime.strptime(start_date, '%Y-%m-%d').date()
            sales_qs = sales_qs.filter(sale_date__gte=start_date)
            payments_qs = payments_qs.filter(payment_date__date__gte=start_date)
            returns_qs = returns_qs.filter(return_date__gte=start_date)
            start_dt = timezone.make_aware(
                datetime.combine(start_date, datetime.min.time()),
                timezone.get_current_timezone(),
            )
            balance_payments_qs = balance_payments_qs.filter(payment_date__gte=start_dt)

        if end_date:
            end_date = datetime.strptime(end_date, '%Y-%m-%d').date()
            sales_qs = sales_qs.filter(sale_date__lte=end_date)
            payments_qs = payments_qs.filter(payment_date__date__lte=end_date)
            returns_qs = returns_qs.filter(return_date__lte=end_date)
            end_dt = timezone.make_aware(
                datetime.combine(end_date + timedelta(days=1), datetime.min.time()),
                timezone.get_current_timezone(),
            )
            balance_payments_qs = balance_payments_qs.filter(payment_date__lt=end_dt)

        # Get data with related fields
        sales = sales_qs.select_related('customer').order_by('-sale_date')
        payments = payments_qs.select_related('sale', 'sale__customer').order_by('-payment_date')
        returns = returns_qs.select_related('sale', 'sale__customer').order_by('-return_date')
        balance_payments = balance_payments_qs.select_related('customer', 'currency').order_by('-payment_date')

        # Serialize data
        sales_data = SaleSerializer(sales, many=True).data
        payments_data = SalePaymentSerializer(payments, many=True).data
        returns_data = SaleReturnSerializer(returns, many=True).data
        balance_payments_data = CustomerBalancePaymentSerializer(balance_payments, many=True).data

        def _sum_amount(val):
            """Sum amount from serializer: can be dict (currency -> amount) or number."""
            if val is None:
                return 0.0
            if isinstance(val, (int, float)):
                return float(val)
            if isinstance(val, dict):
                return sum(float(v) for v in val.values())
            return 0.0

        # Use effective_total_amount (after discount) for sales totals
        total_sales_amount = sum(
            _sum_amount(sale.get('effective_total_amount') or sale.get('total_amount'))
            for sale in sales_data
        )
        total_payments_amount = sum(_sum_amount(payment.get('amount')) for payment in payments_data)
        total_returns_amount = sum(_sum_amount(r.get('total_refound_amount')) for r in returns_data)
        total_balance_payments_amount = sum(_sum_amount(bp.get('amount')) for bp in balance_payments_data)

        net_sales = total_sales_amount - total_returns_amount
        outstanding_amount = total_sales_amount - total_payments_amount - total_returns_amount
        # Revenue = sale payments + balance payments (all cash collected from customers)
        total_revenue = total_payments_amount + total_balance_payments_amount

        summary = {
            'total_sales': len(sales_data),
            'total_payments': len(payments_data),
            'total_returns': len(returns_data),
            'total_balance_payments': len(balance_payments_data),
            'total_sales_amount': total_sales_amount,
            'total_payments_amount': total_payments_amount,
            'total_returns_amount': total_returns_amount,
            'total_balance_payments_amount': total_balance_payments_amount,
            'total_revenue': total_revenue,
            'net_sales_amount': net_sales,
            'outstanding_amount': outstanding_amount,
        }

        return Response({
            'summary': summary,
            'sales': sales_data,
            'payments': payments_data,
            'returns': returns_data,
            'balance_payments': balance_payments_data,
        }, status=status.HTTP_200_OK)
        
    except Exception as e:
        return Response({
            'error': str(e)
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


comprehensive_sale_report.required_tab = "reports"
