from datetime import date, timedelta
from django.utils import timezone
from django.db.models import Q


# =====================================================
# 🔹 DATE RANGE HELPERS
# =====================================================

def get_today_range():
    today = timezone.now().date()
    return today, today


def get_week_range():
    today = timezone.now().date()
    start = today - timedelta(days=today.weekday())  # Monday
    end = start + timedelta(days=6)
    return start, end


def get_month_range():
    today = timezone.now().date()
    start = today.replace(day=1)

    if start.month == 12:
        end = start.replace(year=start.year + 1, month=1, day=1) - timedelta(days=1)
    else:
        end = start.replace(month=start.month + 1, day=1) - timedelta(days=1)

    return start, end


def get_year_range():
    today = timezone.now().date()
    start = today.replace(month=1, day=1)
    end = today.replace(month=12, day=31)
    return start, end


def parse_custom_range(request):
    start = request.GET.get("start_date")
    end = request.GET.get("end_date")

    if start and end:
        return start, end

    return None, None


def resolve_date_filter(request):
    """
    Central handler for date filters:
    ?range=today|week|month|year|custom
    """

    range_type = request.GET.get("range")

    if range_type == "today":
        return get_today_range()

    elif range_type == "week":
        return get_week_range()

    elif range_type == "month":
        return get_month_range()

    elif range_type == "year":
        return get_year_range()

    elif range_type == "custom":
        return parse_custom_range(request)

    return None, None


# =====================================================
# 🔹 SCOPE FILTERS (BUILDING / UNIT / TENANT)
# =====================================================

def get_scope_filters(request):
    return {
        "building": request.GET.get("building"),
        "unit": request.GET.get("unit"),
        "tenant": request.GET.get("tenant"),
    }


def apply_scope_restrictions(queryset, user):
    """
    Enforce role-based data visibility
    """

    if user.role == "landlord":
        return queryset

    if user.role == "caretaker":
        return queryset.filter(unit__building__caretaker=user)

    return queryset.none()


def apply_common_filters(queryset, request, user, date_field="created_at"):
    """
    Apply:
    - date filters
    - building/unit/tenant filters
    - role-based restrictions
    """

    start_date, end_date = resolve_date_filter(request)
    scope = get_scope_filters(request)

    # 🔹 DATE FILTER
    if start_date:
        queryset = queryset.filter(**{f"{date_field}__date__gte": start_date})

    if end_date:
        queryset = queryset.filter(**{f"{date_field}__date__lte": end_date})

    # 🔹 BUILDING FILTER
    if scope["building"]:
        queryset = queryset.filter(unit__building_id=scope["building"])

    # 🔹 UNIT FILTER
    if scope["unit"]:
        queryset = queryset.filter(unit_id=scope["unit"])

    # 🔹 TENANT FILTER
    if scope["tenant"]:
        queryset = queryset.filter(tenant_id=scope["tenant"])

    # 🔹 ROLE-BASED ACCESS
    queryset = apply_scope_restrictions(queryset, user)

    return queryset


# =====================================================
# 🔹 SAFE GETTERS (USED IN VIEWS)
# =====================================================

def get_filtered_payments(request, user):
    from payments.models import Payment

    queryset = Payment.objects.filter(status="completed")

    return apply_common_filters(queryset, request, user)


def get_filtered_invoices(request, user):
    from payments.models import Invoice

    queryset = Invoice.objects.all()

    return apply_common_filters(queryset, request, user)


def get_filtered_expenses(request, user):
    from payments.models import Expense

    queryset = Expense.objects.filter(status="approved")

    return apply_common_filters(queryset, request, user)


# =====================================================
# 🔹 VALIDATION HELPERS
# =====================================================

def safe_int(value):
    try:
        return int(value)
    except (TypeError, ValueError):
        return None


def safe_date(value):
    try:
        return date.fromisoformat(value)
    except Exception:
        return None