from django.db.models import Sum, Count, Q, Value, DecimalField
from django.db.models.functions import TruncDate, TruncHour, Coalesce
from django.http import JsonResponse
from decimal import Decimal
from django.utils.timezone import localtime
from datetime import timedelta
from django.contrib.auth.decorators import login_required

from payments.models import Payment



def get_today_range():
    now = localtime()
    start = now.replace(hour=0, minute=0, second=0, microsecond=0)
    end = start + timedelta(days=1)
    return start, end


def get_month_range():
    now = localtime()
    start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)

    if now.month == 12:
        end = start.replace(year=now.year + 1, month=1)
    else:
        end = start.replace(month=now.month + 1)

    return start, end


def get_year_range():
    now = localtime()
    start = now.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
    end = start.replace(year=now.year + 1)
    return start, end


def to_float(val):
    return float(val) if val is not None else 0


# ---------------------------
# SUMMARY (FIXED)
# ---------------------------

def get_summary():

    def get_totals(queryset):
        return queryset.aggregate(
            stk_total=Coalesce(
                Sum("amount", filter=Q(payment_type="STK", status="SUCCESS")),
                Value(Decimal("0.00")),
                output_field=DecimalField(max_digits=10, decimal_places=2),
            ),
            c2b_total=Coalesce(
                Sum("amount", filter=Q(payment_type="C2B", status="SUCCESS")),
                Value(Decimal("0.00")),
                output_field=DecimalField(max_digits=10, decimal_places=2),
            ),
            total=Coalesce(
                Sum("amount", filter=Q(status="SUCCESS")),
                Value(Decimal("0.00")),
                output_field=DecimalField(max_digits=10, decimal_places=2),
            ),
        )

    #  TODAY
    t_start, t_end = get_today_range()
    today_qs = Payment.objects.filter(created_at__gte=t_start, created_at__lt=t_end)

    #  MONTH
    m_start, m_end = get_month_range()
    month_qs = Payment.objects.filter(created_at__gte=m_start, created_at__lt=m_end)

    #  YEAR
    y_start, y_end = get_year_range()
    year_qs = Payment.objects.filter(created_at__gte=y_start, created_at__lt=y_end)

    return {
        "today": get_totals(today_qs),
        "month": get_totals(month_qs),
        "year": get_totals(year_qs),

        "failed_today": Payment.objects.filter(
            status="FAILED",
            created_at__gte=t_start,
            created_at__lt=t_end,
        ).count(),

        "pending_today": Payment.objects.filter(
            status="PENDING",
            created_at__gte=t_start,
            created_at__lt=t_end,
        ).count(),
    }


# ---------------------------
# DAILY (UNCHANGED - ALREADY GOOD)
# ---------------------------
def daily_breakdown():
    t_start, t_end = get_month_range()

    data = (
        Payment.objects
        .filter(created_at__gte=t_start, created_at__lt=t_end)
        .values("created_at", "status", "payment_type", "amount")
    )

    result = {}

    for row in data:
        date = row["created_at"].strftime("%Y-%m-%d")

        if date not in result:
            result[date] = {
                "date": date,
                "total_amount": 0,
                "success": 0,
                "failed": 0,
                "pending": 0,
                "stk": 0,
                "c2b": 0,
            }

        if row["status"] == "SUCCESS":
            result[date]["total_amount"] += float(row["amount"])
            result[date]["success"] += 1

            if row["payment_type"] == "STK":
                result[date]["stk"] += 1
            else:
                result[date]["c2b"] += 1

        elif row["status"] == "FAILED":
            result[date]["failed"] += 1
        else:
            result[date]["pending"] += 1

    return sorted(result.values(), key=lambda x: x["date"], reverse=True)



def hourly_stats():
    t_start, t_end = get_today_range()

    data = (
        Payment.objects
        .filter(created_at__gte=t_start, created_at__lt=t_end)
        .values("created_at", "status")
    )

    result = {}

    for row in data:
        local_dt = localtime(row["created_at"])  
        hour = local_dt.strftime("%H:00")         

        if hour not in result:
            result[hour] = {
                "hour": hour,
                "total": 0,
                "success": 0,
                "failed": 0,
                "pending": 0,
            }

        result[hour]["total"] += 1

        if row["status"] == "SUCCESS":
            result[hour]["success"] += 1
        elif row["status"] == "FAILED":
            result[hour]["failed"] += 1
        else:
            result[hour]["pending"] += 1

    return list(result.values())
# ---------------------------
# DASHBOARD API 
# ---------------------------
@login_required
def dashboard_data(request):
    summary = get_summary()

    return JsonResponse({
        "today": {
            "total": to_float(summary["today"]["total"]),
            "stk": to_float(summary["today"]["stk_total"]),
            "c2b": to_float(summary["today"]["c2b_total"]),
            "failed": summary["failed_today"],
            "pending": summary["pending_today"],
        },
        # Month
        "month": {
            "total": to_float(summary["month"]["total"]),
            "stk": to_float(summary["month"]["stk_total"]),
            "c2b": to_float(summary["month"]["c2b_total"]),
        },

        # year
        "year": {
            "total": to_float(summary["year"]["total"]),
            "stk": to_float(summary["year"]["stk_total"]),
            "c2b": to_float(summary["year"]["c2b_total"]),
        },
        "hourly": hourly_stats(),
    })