import json
from decimal import Decimal

from django.contrib.auth.decorators import login_required
from django.db.models import Sum
from django.shortcuts import render, redirect

from contributions.models import Contribution
from contractors.models import Contractor
from core.models import Project, AuditLog
from core.project_utils import get_allowed_projects, get_current_project, set_current_project
from expenses.models import Expense, ExpenseCategory
from finance.models import BankAccount, CashTransaction
from labor.models import Worker
from materials.models import Material
from members.models import Member


def _d(value):
    return float(value) if value is not None else 0.0


@login_required
def home(request):
    if request.user.is_superuser:
        return redirect("accounts:super_admin_home")

    allowed_projects = get_allowed_projects(request.user)
    project = get_current_project(request)
    requested_project = request.GET.get("project")
    if requested_project:
        candidate = allowed_projects.filter(id=requested_project).first()
        if candidate:
            set_current_project(request, candidate)
            project = candidate

    if not project:
        return render(request, "dashboard/no_project.html")

    members = Member.objects.filter(project_id=project.pk)
    total_members = members.filter(is_active=True).count()

    total_contribution = Contribution.objects.filter(member__project_id=project.pk).aggregate(
        t=Sum("amount"))["t"] or Decimal("0")
    total_starting_balance = members.filter(is_active=True).aggregate(
        t=Sum("starting_balance"))["t"] or Decimal("0")
    total_member_balance = total_starting_balance + total_contribution

    total_expense = Expense.objects.filter(project_id=project.pk).aggregate(t=Sum("amount"))["t"] or Decimal("0")

    bank_accounts = BankAccount.objects.filter(project_id=project.pk)
    bank_balance = sum((b.current_balance for b in bank_accounts), Decimal("0"))

    cash_in = CashTransaction.objects.filter(project_id=project.pk, txn_type="in").aggregate(
        t=Sum("amount"))["t"] or Decimal("0")
    cash_out = CashTransaction.objects.filter(project_id=project.pk, txn_type="out").aggregate(
        t=Sum("amount"))["t"] or Decimal("0")
    # Cash position = manual cash-in/out entries + member contributions received as cash
    # minus expenses paid as cash (kept simple/transparent for a first cut).
    cash_balance = cash_in - cash_out

    material_stock_value = Decimal("0")
    for m in Material.objects.filter(project_id=project.pk):
        remaining = m.remaining_stock
        purchased = m.total_purchased
        if purchased:
            avg_price = m.total_purchase_value / purchased
            material_stock_value += remaining * avg_price

    contractor_due = sum(
        (c.remaining_amount for c in Contractor.objects.filter(project_id=project.pk)), Decimal("0")
    )
    worker_due = sum(
        (w.due_amount for w in Worker.objects.filter(project_id=project.pk)), Decimal("0")
    )
    total_due = contractor_due + worker_due

    # Expense by category (for the pie chart)
    expense_by_category = list(
        Expense.objects.filter(project_id=project.pk)
        .values("category__name")
        .annotate(total=Sum("amount"))
        .order_by("-total")[:8]
    )
    chart_labels = [row["category__name"] or "Uncategorized" for row in expense_by_category]
    chart_values = [_d(row["total"]) for row in expense_by_category]

    # Monthly contribution vs expense trend (last 6 months)
    from django.utils import timezone
    from dateutil.relativedelta import relativedelta
    today = timezone.now().date()
    months = []
    contrib_trend = []
    expense_trend = []
    for i in range(5, -1, -1):
        month_date = (today.replace(day=1) - relativedelta(months=i))
        next_month = month_date + relativedelta(months=1)
        months.append(month_date.strftime("%b %Y"))
        contrib_trend.append(_d(
            Contribution.objects.filter(
                member__project_id=project.pk, date__gte=month_date, date__lt=next_month
            ).aggregate(t=Sum("amount"))["t"]
        ))
        expense_trend.append(_d(
            Expense.objects.filter(
                project=project, date__gte=month_date, date__lt=next_month
            ).aggregate(t=Sum("amount"))["t"]
        ))

    recent_deposits = Contribution.objects.filter(member__project_id=project.pk).select_related("member")[:5]
    recent_expenses = Expense.objects.filter(project_id=project.pk).select_related("category")[:5]
    recent_audit = AuditLog.objects.filter(project_id=project.pk).select_related("user")[:8]

    member_balance_list = sorted(
        [m for m in members if m.is_active and m.current_balance > 0],
        key=lambda m: -m.current_balance
    )[:8]

    # Member-wise deposit summary for the main dashboard.  This is a read-only
    # view and does not alter the existing deposit/contributor workflow.
    member_deposit_rows = []
    for member in members.filter(is_active=True):
        total_deposit = Contribution.objects.filter(member_id=member.pk).aggregate(
            t=Sum("amount")
        )["t"] or Decimal("0")
        latest_deposit = Contribution.objects.filter(member_id=member.pk).order_by("-date", "-created_at").first()
        member_deposit_rows.append({
            "member": member,
            "deposit_total": total_deposit,
            "latest_date": latest_deposit.date if latest_deposit else None,
            "current_balance": member.starting_balance + total_deposit,
        })
    member_deposit_rows.sort(key=lambda row: (-row["deposit_total"], row["member"].full_name.lower()))
    member_deposit_rows = member_deposit_rows[:10]

    context = {
        "project": project,
        "all_projects": allowed_projects,
        "total_members": total_members,
        "total_contribution": total_contribution,
        "total_starting_balance": total_starting_balance,
        "total_member_balance": total_member_balance,
        "total_expense": total_expense,
        "bank_balance": bank_balance,
        "cash_balance": cash_balance,
        "material_stock_value": material_stock_value,
        "contractor_due": contractor_due,
        "worker_due": worker_due,
        "recent_deposits": recent_deposits,
        "member_deposit_rows": member_deposit_rows,
        "recent_expenses": recent_expenses,
        "recent_audit": recent_audit,
        "member_balance_list": member_balance_list,
        "chart_category_labels": json.dumps(chart_labels),
        "chart_category_values": json.dumps(chart_values),
        "chart_months": json.dumps(months),
        "chart_contrib_trend": json.dumps(contrib_trend),
        "chart_expense_trend": json.dumps(expense_trend),
    }
    return render(request, "dashboard/home.html", context)


@login_required
def switch_project(request, project_id):
    project = get_allowed_projects(request.user).filter(id=project_id).first()
    if project:
        set_current_project(request, project)
    return redirect("dashboard:home")
