from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required, user_passes_test
from .models import Income, Expense, Category, UserSettings
from django.contrib import messages
from django.db import models
from django import forms
from django.utils import timezone
import csv
from django.http import HttpResponse
from datetime import datetime
from django.contrib.auth.forms import UserChangeForm
from django.contrib.auth.models import User

def admin_required(user):
    return user.is_active and user.is_superuser

class IncomeForm(forms.ModelForm):
    class Meta:
        model = Income
        fields = ['source', 'amount', 'date']
        widgets = {
            'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'source': forms.TextInput(attrs={'class': 'form-control'}),
            'amount': forms.NumberInput(attrs={'class': 'form-control'}),
        }

    def clean_amount(self):
        amount = self.cleaned_data['amount']
        if amount < 0:
            raise forms.ValidationError('Amount cannot be negative.')
        return amount

    def clean_date(self):
        date = self.cleaned_data['date']
        if date > timezone.now().date():
            raise forms.ValidationError('Date cannot be in the future.')
        return date

class ExpenseForm(forms.ModelForm):
    class Meta:
        model = Expense
        fields = ['title', 'category', 'amount', 'date', 'description']
        widgets = {
            'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'category': forms.TextInput(attrs={'class': 'form-control'}),
            'amount': forms.NumberInput(attrs={'class': 'form-control'}),
            'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
        }

    def clean_amount(self):
        amount = self.cleaned_data['amount']
        if amount < 0:
            raise forms.ValidationError('Amount cannot be negative.')
        return amount

    def clean_date(self):
        date = self.cleaned_data['date']
        if date > timezone.now().date():
            raise forms.ValidationError('Date cannot be in the future.')
        return date

class CategoryForm(forms.ModelForm):
    class Meta:
        model = Category
        fields = ['name']
        widgets = {
            'name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Category Name'})
        }

class BudgetCurrencyForm(forms.ModelForm):
    class Meta:
        model = UserSettings
        fields = ['monthly_budget', 'yearly_budget', 'preferred_currency']
        widgets = {
            'monthly_budget': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
            'yearly_budget': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
            'preferred_currency': forms.Select(attrs={'class': 'form-select'}, choices=[('USD','USD'),('EUR','EUR'),('PKR','PKR'),('INR','INR'),('GBP','GBP')]),
        }

class ProfileForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'email']
        widgets = {
            'first_name': forms.TextInput(attrs={'class': 'form-control'}),
            'last_name': forms.TextInput(attrs={'class': 'form-control'}),
            'email': forms.EmailInput(attrs={'class': 'form-control'}),
        }

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def dashboard(request):
    # Remove old total calculations
    # total_income = Income.objects.aggregate(total=models.Sum('amount'))['total'] or 0
    # total_expense = Expense.objects.aggregate(total=models.Sum('amount'))['total'] or 0
    # net = total_income - total_expense
    # Instead, use monthly_income, monthly_expense, monthly_net for the summary cards
    latest_incomes = Income.objects.order_by('-date')[:5]
    latest_expenses = Expense.objects.order_by('-date')[:5]

    today = timezone.now().date()
    # Month filter logic
    month_str = request.GET.get('month')
    if month_str:
        try:
            month_date = datetime.strptime(month_str, '%Y-%m')
            month_start = month_date.replace(day=1).date()
            if month_start.month == 12:
                next_month = month_start.replace(year=month_start.year+1, month=1, day=1)
            else:
                next_month = month_start.replace(month=month_start.month+1, day=1)
            month_end = next_month - timezone.timedelta(days=1)
        except Exception:
            month_start = today.replace(day=1)
            month_end = today
    else:
        month_start = today.replace(day=1)
        month_end = today

    monthly_income = Income.objects.filter(date__gte=month_start, date__lte=month_end).aggregate(total=models.Sum('amount'))['total'] or 0
    monthly_expense = Expense.objects.filter(date__gte=month_start, date__lte=month_end).aggregate(total=models.Sum('amount'))['total'] or 0
    monthly_net = monthly_income - monthly_expense

    year_start = today.replace(month=1, day=1)
    yearly_income = Income.objects.filter(date__gte=year_start, date__lte=today).aggregate(total=models.Sum('amount'))['total'] or 0
    yearly_expense = Expense.objects.filter(date__gte=year_start, date__lte=today).aggregate(total=models.Sum('amount'))['total'] or 0
    yearly_net = yearly_income - yearly_expense

    # Filter incomes and expenses for the selected month
    latest_incomes = Income.objects.filter(date__gte=month_start, date__lte=month_end).order_by('-date')
    latest_expenses = Expense.objects.filter(date__gte=month_start, date__lte=month_end).order_by('-date')

    currency = request.user.settings.preferred_currency if hasattr(request.user, 'settings') else 'USD'
    monthly_budget = request.user.settings.monthly_budget if hasattr(request.user, 'settings') else 0
    over_budget = monthly_expense > monthly_budget if monthly_budget > 0 else False
    budget_diff = abs(monthly_expense - monthly_budget) if monthly_budget > 0 else 0
    budget_percent = int((monthly_expense / monthly_budget) * 100) if monthly_budget > 0 else 0
    if budget_percent > 100:
        budget_percent = 100
    context = {
        'total_income': monthly_income,
        'total_expense': monthly_expense,
        'net': monthly_net,
        'abs_net': abs(monthly_net),
        'latest_incomes': latest_incomes,
        'latest_expenses': latest_expenses,
        'monthly_income': monthly_income,
        'monthly_expense': monthly_expense,
        'monthly_net': monthly_net,
        'yearly_income': yearly_income,
        'yearly_expense': yearly_expense,
        'yearly_net': yearly_net,
        'selected_month': month_str or today.strftime('%Y-%m'),
        'currency': currency,
        'monthly_budget': monthly_budget,
        'over_budget': over_budget,
        'budget_diff': budget_diff,
        'budget_percent': budget_percent,
    }
    return render(request, 'dashboard.html', context)

# Add a new view for root redirect
def root_redirect(request):
    return redirect('/login/')

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def add_income(request):
    if request.method == 'POST':
        form = IncomeForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'Income added successfully!')
            return redirect('dashboard')
        else:
            messages.error(request, 'Please correct the errors below.')
    else:
        form = IncomeForm()
    return render(request, 'add_income.html', {'form': form})

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def add_expense(request):
    if request.method == 'POST':
        form = ExpenseForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'Expense added successfully!')
            return redirect('dashboard')
        else:
            messages.error(request, 'Please correct the errors below.')
    else:
        form = ExpenseForm()
    return render(request, 'add_expense.html', {'form': form})

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def edit_income(request, pk):
    income = get_object_or_404(Income, pk=pk)
    if request.method == 'POST':
        form = IncomeForm(request.POST, instance=income)
        if form.is_valid():
            form.save()
            messages.success(request, 'Income updated successfully!')
            return redirect('dashboard')
        else:
            messages.error(request, 'Please correct the errors below.')
    else:
        form = IncomeForm(instance=income)
    return render(request, 'edit_income.html', {'form': form, 'income': income})

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def delete_income(request, pk):
    income = get_object_or_404(Income, pk=pk)
    if request.method == 'POST':
        income.delete()
        messages.success(request, 'Income deleted successfully!')
        return redirect('dashboard')
    return render(request, 'delete_income.html', {'income': income})

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def edit_expense(request, pk):
    expense = get_object_or_404(Expense, pk=pk)
    if request.method == 'POST':
        form = ExpenseForm(request.POST, instance=expense)
        if form.is_valid():
            form.save()
            messages.success(request, 'Expense updated successfully!')
            return redirect('dashboard')
        else:
            messages.error(request, 'Please correct the errors below.')
    else:
        form = ExpenseForm(instance=expense)
    return render(request, 'edit_expense.html', {'form': form, 'expense': expense})

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def delete_expense(request, pk):
    expense = get_object_or_404(Expense, pk=pk)
    if request.method == 'POST':
        expense.delete()
        messages.success(request, 'Expense deleted successfully!')
        return redirect('dashboard')
    return render(request, 'delete_expense.html', {'expense': expense})

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def export_income_csv(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="income.csv"'
    writer = csv.writer(response)
    writer.writerow(['Source', 'Amount', 'Date'])
    for income in Income.objects.all():
        writer.writerow([income.source, income.amount, income.date])
    return response

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def export_expense_csv(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="expense.csv"'
    writer = csv.writer(response)
    writer.writerow(['Title', 'Category', 'Amount', 'Date', 'Description'])
    for expense in Expense.objects.all():
        writer.writerow([expense.title, expense.category, expense.amount, expense.date, expense.description])
    return response

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def categories(request):
    categories = Category.objects.all().order_by('name')
    form = CategoryForm()
    if request.method == 'POST':
        form = CategoryForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'Category added successfully!')
            return redirect('categories')
        else:
            messages.error(request, 'Please correct the errors below.')
    return render(request, 'categories.html', {'categories': categories, 'form': form})

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def edit_category(request, pk):
    category = get_object_or_404(Category, pk=pk)
    if request.method == 'POST':
        form = CategoryForm(request.POST, instance=category)
        if form.is_valid():
            form.save()
            messages.success(request, 'Category updated successfully!')
            return redirect('categories')
        else:
            messages.error(request, 'Please correct the errors below.')
    else:
        form = CategoryForm(instance=category)
    return render(request, 'edit_category.html', {'form': form, 'category': category})

@login_required(login_url='/login/')
@user_passes_test(admin_required, login_url='/login/')
def delete_category(request, pk):
    category = get_object_or_404(Category, pk=pk)
    if request.method == 'POST':
        category.delete()
        messages.success(request, 'Category deleted successfully!')
        return redirect('categories')
    return render(request, 'delete_category.html', {'category': category})

def analytics(request):
    return render(request, 'analytics.html')

@login_required(login_url='/login/')
def settings(request):
    user = request.user
    # Ensure UserSettings exists
    if not hasattr(user, 'settings'):
        from core.models import UserSettings
        UserSettings.objects.create(user=user)
    settings_obj = user.settings
    budget_form = BudgetCurrencyForm(request.POST or None, instance=settings_obj)
    profile_form = ProfileForm(request.POST or None, instance=user)
    if request.method == 'POST':
        if 'save_budget' in request.POST and budget_form.is_valid():
            budget_form.save()
            messages.success(request, 'Budget and currency updated!')
            return redirect('settings')
        if 'save_profile' in request.POST and profile_form.is_valid():
            profile_form.save()
            messages.success(request, 'Profile updated!')
            return redirect('settings')
    return render(request, 'settings.html', {
        'budget_form': budget_form,
        'profile_form': profile_form,
    })
