from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib import messages
from django.http import JsonResponse
from django.utils import timezone
from datetime import timedelta, date
from decimal import Decimal
from .models import Invoice, BillingCycle
from customers.models import Customer, Package
from django.core.paginator import Paginator
from django.views.generic import ListView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from accounts.permissions import (
    has_financial_access,
    EmployeeRequiredMixin,
    CustomerRequiredMixin,
    permission_required,
    has_permission,
    get_user_permissions
)

def is_admin(user):
    return user.is_staff or user.is_superuser

@login_required
@user_passes_test(is_admin)
def invoice_list(request):
    invoices = Invoice.objects.all().order_by('-created_at')

    # Filter by status
    status_filter = request.GET.get('status')
    if status_filter:
        invoices = invoices.filter(status=status_filter)

    # Filter by customer
    customer_filter = request.GET.get('customer')
    if customer_filter:
        invoices = invoices.filter(customer__id=customer_filter)

    paginator = Paginator(invoices, 25)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    customers = Customer.objects.all()

    context = {
        'page_obj': page_obj,
        'customers': customers,
        'status_filter': status_filter,
        'customer_filter': customer_filter,
    }
    return render(request, 'billing/invoice_list.html', context)

@login_required
@permission_required('billing.view_invoice')
def invoice_detail(request, invoice_number):
    invoice = get_object_or_404(Invoice, invoice_number=invoice_number)
    return render(request, 'billing/invoice_detail.html', {'invoice': invoice})

@login_required
@permission_required('billing.add_invoice')
def create_invoice(request):
    if request.method == 'POST':
        customer_id = request.POST.get('customer')
        package_id = request.POST.get('package')
        billing_period_start = request.POST.get('billing_period_start')
        billing_period_end = request.POST.get('billing_period_end')
        installation_fee = request.POST.get('installation_fee', 0)
        notes = request.POST.get('notes', '')

        customer = get_object_or_404(Customer, id=customer_id)
        package = get_object_or_404(Package, id=package_id)

        # Calculate due date based on billing cycle
        issue_date = timezone.now().date()
        if package.billing_cycle == 'monthly':
            due_date = issue_date + timedelta(days=30)
        elif package.billing_cycle == 'quarterly':
            due_date = issue_date + timedelta(days=90)
        else:  # annually
            due_date = issue_date + timedelta(days=365)

        invoice = Invoice.objects.create(
            customer=customer,
            package=package,
            package_amount=package.price,
            installation_fee=Decimal(installation_fee),
            issue_date=issue_date,
            due_date=due_date,
            billing_period_start=billing_period_start,
            billing_period_end=billing_period_end,
            notes=notes
        )

        messages.success(request, f'Invoice {invoice.invoice_number} created successfully!')
        return redirect('billing:invoice_detail', invoice_number=invoice.invoice_number)

    customers = Customer.objects.filter(is_active=True)
    packages = Package.objects.filter(is_active=True)

    context = {
        'customers': customers,
        'packages': packages,
    }
    return render(request, 'billing/create_invoice.html', context)

@login_required
def my_invoices(request):
    """View for clients to see their own invoices"""
    if not hasattr(request.user, 'customer_profile'):
        messages.error(request, "You don't have a customer profile.")
        return redirect('customers:dashboard')

    invoices = Invoice.objects.filter(
        customer=request.user.customer_profile
    ).order_by('-created_at')

    paginator = Paginator(invoices, 25)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'page_obj': page_obj,
    }
    return render(request, 'billing/my_invoices.html', context)

@login_required
@permission_required('billing.generate_recurring_invoices')
def generate_recurring_invoices(request):
    if request.method == 'POST':
        billing_cycles = BillingCycle.objects.filter(
            next_billing_date__lte=timezone.now().date(),
            is_active=True
        )

        created_count = 0
        for cycle in billing_cycles:
            customer = cycle.customer
            if customer.package and customer.is_active:
                # Calculate billing period
                today = timezone.now().date()
                if customer.package.billing_cycle == 'monthly':
                    period_start = today
                    period_end = today + timedelta(days=30)
                    next_billing = today + timedelta(days=30)
                elif customer.package.billing_cycle == 'quarterly':
                    period_start = today
                    period_end = today + timedelta(days=90)
                    next_billing = today + timedelta(days=90)
                else:  # annually
                    period_start = today
                    period_end = today + timedelta(days=365)
                    next_billing = today + timedelta(days=365)

                # Create invoice
                invoice = Invoice.objects.create(
                    customer=customer,
                    package=customer.package,
                    package_amount=customer.package.price,
                    issue_date=today,
                    due_date=today + timedelta(days=7),  # 7 days to pay
                    billing_period_start=period_start,
                    billing_period_end=period_end,
                )

                # Update next billing date
                cycle.next_billing_date = next_billing
                cycle.save()

                created_count += 1

        messages.success(request, f'Generated {created_count} recurring invoices!')
        return redirect('billing:invoice_list')

    return render(request, 'billing/generate_recurring.html')

@login_required
@permission_required('billing.view_customer_invoices')
def customer_invoices(request, customer_id):
    """View for admin to see all invoices for a specific customer"""
    customer = get_object_or_404(Customer, customer_id=customer_id)
    invoices = Invoice.objects.filter(customer=customer).order_by('-created_at')

    paginator = Paginator(invoices, 25)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'customer': customer,
        'page_obj': page_obj,
    }
    return render(request, 'billing/customer_invoices.html', context)

class MyInvoicesView(CustomerRequiredMixin, ListView):
    model = Invoice
    template_name = 'billing/my_invoices.html'
    context_object_name = 'invoices'
    paginate_by = 10

    def get_queryset(self):
        if hasattr(self.request.user, 'customer_profile'):
            return Invoice.objects.filter(customer=self.request.user.customer_profile).order_by('-created_at')
        return Invoice.objects.none()

class CustomerInvoicesView(UserPassesTestMixin, ListView):
    model = Invoice
    template_name = 'billing/customer_invoices.html'
    context_object_name = 'invoices'
    paginate_by = 10

    def test_func(self):
        return has_permission(self.request.user, 'billing.view_customer_invoices')

    def get_queryset(self):
        customer_id = self.kwargs['customer_id']
        customer = get_object_or_404(Customer, customer_id=customer_id)
        return Invoice.objects.filter(customer=customer).order_by('-created_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        customer_id = self.kwargs['customer_id']
        context['customer'] = get_object_or_404(Customer, customer_id=customer_id)
        return context