from django.contrib import admin
from django.shortcuts import render, redirect
from django.utils.html import format_html
from django.urls import path
from django.http import HttpResponseRedirect
from django import forms
from django.db.models import Sum, Count, Avg
from datetime import datetime, timedelta
from django.utils import timezone

from .models import (
    Product, Color, Size, Order, OrderItem, GuestUser, Coupon, CouponUsage,
    OrderStatus, ShippingAddress
)

class ShopAdminSite(admin.AdminSite):
    site_header = "Shop Administration"
    site_title = "Shop Admin Portal"
    index_title = "Welcome to Shop Administration"

    def index(self, request, extra_context=None):
        """Custom admin index view with dashboard"""
        # Calculate order statistics
        order_status_data = []
        total_orders = Order.objects.count()
        total_revenue = Order.objects.aggregate(Sum('total_price'))['total_price__sum'] or 0

        # Get data for each status
        for status_choice in OrderStatus.choices:
            status_code, status_label = status_choice
            orders_for_status = Order.objects.filter(status=status_code)
            count = orders_for_status.count()
            total_amount = orders_for_status.aggregate(Sum('total_price'))['total_price__sum'] or 0
            avg_order_value = orders_for_status.aggregate(Avg('total_price'))['total_price__avg'] or 0
            percentage = (count / total_orders * 100) if total_orders > 0 else 0

            order_status_data.append({
                'status': status_code,
                'label': status_label,
                'count': count,
                'total_amount': total_amount,
                'avg_order_value': avg_order_value,
                'percentage': percentage
            })

        # Recent activity calculations
        now = timezone.now()
        today = now.date()
        week_ago = today - timedelta(days=7)
        month_ago = today - timedelta(days=30)

        orders_today = Order.objects.filter(date_ordered__date=today).count()
        orders_this_week = Order.objects.filter(date_ordered__date__gte=week_ago).count()
        orders_this_month = Order.objects.filter(date_ordered__date__gte=month_ago).count()
        orders_to_prepare = Order.objects.filter(status=OrderStatus.PAID).count()

        extra_context = extra_context or {}
        extra_context.update({
            'order_status_data': order_status_data,
            'total_orders': total_orders,
            'total_revenue': total_revenue,
            'orders_today': orders_today,
            'orders_this_week': orders_this_week,
            'orders_this_month': orders_this_month,
            'orders_to_prepare': orders_to_prepare,
        })

        return render(request, 'admin/shop/dashboard.html', extra_context)

# Create an instance of the custom admin site
shop_admin_site = ShopAdminSite(name='shop_admin')

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ("title", "ordering_value", "price", "cut")
    search_fields = ["title", "description"]  # Enable search for autocomplete

@admin.register(Color)
class ColorAdmin(admin.ModelAdmin):
    list_display = ("color_preview", "name", "ordering", "colorHex", "secondary_hex_color")
    list_editable = ("ordering",)
    ordering = ["ordering"]
    search_fields = ["name"]
    list_per_page = 20

    def color_preview(self, obj):
        if obj.secondary_hex_color:
            return format_html(
                '<div style="background-image: linear-gradient(to right, {} 50%, {} 50%); '
                'width: 60px; height: 30px; border-radius: 15px; border: 1px solid #ddd;"></div>',
                obj.colorHex, obj.secondary_hex_color
            )
        return format_html(
            '<div style="background-color: {}; width: 60px; height: 30px; '
            'border-radius: 15px; border: 1px solid #ddd;"></div>',
            obj.colorHex
        )

@admin.register(Size)
class SizeAdmin(admin.ModelAdmin):
    list_display = ("name",)

class OrderItemInline(admin.TabularInline):
    model = OrderItem
    extra = 1  # Show one extra row for adding new items
    autocomplete_fields = ['product']  # Enable product search
    fields = ('product', 'quantity', 'color', 'size', 'price')

@admin.register(OrderItem)
class OrderItemAdmin(admin.ModelAdmin):
    list_display = ('order', 'product', 'quantity', 'color', 'size', 'price', 'get_total_price')
    list_filter = ('product', 'color', 'size', 'order__status')
    search_fields = ('order__id', 'product__title', 'order__user__email', 'order__guest_user__email')
    autocomplete_fields = ['order', 'product']
    list_editable = ('quantity', 'price')

    def get_total_price(self, obj):
        return obj.get_total_price()
    get_total_price.short_description = 'Total Price'
    get_total_price.admin_order_field = 'price'  # Allows column to be sortable

@admin.register(ShippingAddress)
class ShippingAddressAdmin(admin.ModelAdmin):
    list_display = ('street_address', 'city', 'postal_code', 'country')
    search_fields = ('street_address', 'city', 'postal_code', 'country')

class ChangeOrderStatusForm(forms.Form):
    _selected_action = forms.CharField(widget=forms.MultipleHiddenInput)
    status = forms.ChoiceField(choices=OrderStatus.choices, label="New Status")

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    list_display = ('id', 'get_email', 'date_ordered', 'status', 'total_price', 'get_shipping_address')
    inlines = [OrderItemInline]
    list_filter = ('status', 'payment_status')
    readonly_fields = ('shipping_address_details',)
    actions = ['change_order_status']
    autocomplete_fields = ['user']  # Add this line for user search functionality
    search_fields = ['id', 'user__email', 'user__username', 'guest_user__email']  # Add this line

    def get_email(self, obj):
        if obj.guest_user:
            return obj.guest_user.email
        else:
            return obj.user.email
    get_email.short_description = 'Email'

    def get_shipping_address(self, obj):
        if obj.shipping_address:
            return f"{obj.shipping_address.street_address}, {obj.shipping_address.city}"
        return "No shipping address"
    get_shipping_address.short_description = 'Shipping Address'

    def shipping_address_details(self, obj):
        if obj.shipping_address:
            return format_html(
                """
                <div style="padding: 10px; background-color: #f9f9f9; border-radius: 4px;">
                    <strong>Street:</strong> {}<br>
                    {}
                    <strong>City:</strong> {}<br>
                    <strong>State:</strong> {}<br>
                    <strong>Postal Code:</strong> {}<br>
                    <strong>Country:</strong> {}
                </div>
                """,
                obj.shipping_address.street_address,
                f"<strong>Apartment:</strong> {obj.shipping_address.apartment}<br>" if obj.shipping_address.apartment else "",
                obj.shipping_address.city,
                obj.shipping_address.state,
                obj.shipping_address.postal_code,
                obj.shipping_address.country,
            )
        return "No shipping address set"
    shipping_address_details.short_description = 'Shipping Address Details'

    fieldsets = (
        (None, {
            'fields': ('user', 'guest_user', 'status', 'payment_status', 'total_price')
        }),
        ('Shipping Information', {
            'fields': ('shipping_address_details',),
        }),
        ('Payment Details', {
            'fields': ('stripe_payment_intent_id', 'stripe_checkout_session_id', 'stripe_mode'),
            'classes': ('collapse',)
        }),
        ('Discount Information', {
            'fields': ('coupon', 'discount_amount'),
            'classes': ('collapse',)
        }),
    )

    def dashboard_view(self, request):
        """Dashboard view with order statistics"""
        # Calculate order statistics
        order_status_data = []
        total_orders = Order.objects.count()
        total_revenue = Order.objects.aggregate(Sum('total_price'))['total_price__sum'] or 0

        # Get data for each status
        for status_choice in OrderStatus.choices:
            status_code, status_label = status_choice
            orders_for_status = Order.objects.filter(status=status_code)
            count = orders_for_status.count()
            total_amount = orders_for_status.aggregate(Sum('total_price'))['total_price__sum'] or 0
            avg_order_value = orders_for_status.aggregate(Avg('total_price'))['total_price__avg'] or 0
            percentage = (count / total_orders * 100) if total_orders > 0 else 0

            order_status_data.append({
                'status': status_code,
                'label': status_label,
                'count': count,
                'total_amount': total_amount,
                'avg_order_value': avg_order_value,
                'percentage': percentage
            })

        # Recent activity calculations
        now = timezone.now()
        today = now.date()
        week_ago = today - timedelta(days=7)
        month_ago = today - timedelta(days=30)

        orders_today = Order.objects.filter(date_ordered__date=today).count()
        orders_this_week = Order.objects.filter(date_ordered__date__gte=week_ago).count()
        orders_this_month = Order.objects.filter(date_ordered__date__gte=month_ago).count()
        orders_to_prepare = Order.objects.filter(status=OrderStatus.PAID).count()

        context = {
            'title': 'Shop Dashboard',
            'app_label': 'shop',
            'opts': Order._meta,
            'order_status_data': order_status_data,
            'total_orders': total_orders,
            'total_revenue': total_revenue,
            'orders_today': orders_today,
            'orders_this_week': orders_this_week,
            'orders_this_month': orders_this_month,
            'orders_to_prepare': orders_to_prepare,
        }

        return render(request, 'admin/shop/dashboard.html', context)

    def changelist_view(self, request, extra_context=None):
        # If 'show_preparation' parameter is in the request, show the preparation view
        if 'show_preparation' in request.GET:
            return self.preparation_view(request)

        # Otherwise show the normal change list
        extra_context = extra_context or {}
        paid_orders_count = Order.objects.filter(status=OrderStatus.PAID).count()
        extra_context['paid_orders_count'] = paid_orders_count
        return super().changelist_view(request, extra_context=extra_context)

    def preparation_view(self, request):
        """View for items that need to be prepared"""
        # Get paid orders
        orders = Order.objects.filter(status=OrderStatus.PAID).order_by('-date_ordered')

        # Group items by product, color, size
        items_by_variant = {}
        all_items = OrderItem.objects.filter(order__status=OrderStatus.PAID)

        for item in all_items:
            # Create a key for grouping items
            key = (
                str(item.product.id),
                str(item.color.id) if item.color else 'none',
                str(item.size.id) if item.size else 'none'
            )

            if key not in items_by_variant:
                items_by_variant[key] = {
                    'product': item.product,
                    'color': item.color,
                    'size': item.size,
                    'quantity': 0,
                    'orders': set()
                }

            items_by_variant[key]['quantity'] += item.quantity
            items_by_variant[key]['orders'].add(item.order.id)

        # Convert to list and sort
        items_list = list(items_by_variant.values())
        items_list.sort(key=lambda x: x['product'].title)

        context = {
            'title': 'Orders to Prepare',
            'app_label': 'shop',
            'opts': Order._meta,
            'orders': orders,
            'items': items_list,
            'total_orders': orders.count(),
            'total_items': sum(i['quantity'] for i in items_list)
        }

        return render(
            request,
            'admin/shop/order/preparation_view.html',
            context
        )

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path('dashboard/', self.admin_site.admin_view(self.dashboard_view), name='shop_order_dashboard'),
            path('prepare-all/', self.admin_site.admin_view(self.prepare_all_orders), name='prepare_all_orders'),
            path('<int:order_id>/prepare/', self.admin_site.admin_view(self.prepare_order), name='prepare_order'),
            path('<int:order_id>/cancel-refund/', self.admin_site.admin_view(self.cancel_and_refund_order), name='cancel_and_refund_order'),
        ]
        return custom_urls + urls

    def prepare_all_orders(self, request):
        if request.method == 'POST':
            Order.objects.filter(status=OrderStatus.PAID).update(status=OrderStatus.PREPARED)
            self.message_user(request, "All orders have been marked as prepared.")
        return redirect('admin:shop_order_changelist')

    def prepare_order(self, request, order_id):
        if request.method == 'POST':
            order = Order.objects.get(id=order_id)
            order.status = OrderStatus.PREPARED
            order.save()
            self.message_user(request, f"Order #{order_id} has been marked as prepared.")
        return redirect('admin:shop_order_changelist')

    def cancel_and_refund_order(self, request, order_id):
        if request.method == 'POST':
            order = Order.objects.get(id=order_id)
            try:
                # Reuse the cancel_order logic from your views
                from .views import cancel_order
                cancel_order(request, order_id)
                self.message_user(request, f"Order #{order_id} has been cancelled and refunded.")
            except Exception as e:
                self.message_user(request, f"Error cancelling order: {str(e)}", level='ERROR')
        return redirect('admin:shop_order_changelist')

    def change_order_status(self, request, queryset):
        """Admin action to change the status of selected orders"""
        form = None

        if 'apply' in request.POST:
            form = ChangeOrderStatusForm(request.POST)

            if form.is_valid():
                status = form.cleaned_data['status']
                count = 0

                for order in queryset:
                    order.status = status
                    order.save()
                    count += 1

                self.message_user(request, f"{count} orders have been updated to status '{OrderStatus(status).label}'.")
                return HttpResponseRedirect(request.get_full_path())

        if not form:
            form = ChangeOrderStatusForm(initial={'_selected_action': request.POST.getlist('_selected_action')})

        context = {
            'title': 'Change Order Status',
            'orders': queryset,
            'form': form,
            'action': 'change_order_status'
        }
        return render(request, 'admin/shop/order/change_status.html', context)

    change_order_status.short_description = "Change status for selected orders"

class GuestUserOrderInline(admin.TabularInline):
    model = Order
    extra = 0
    readonly_fields = ('date_ordered', 'total_price')
    can_delete = False
    show_change_link = True
    exclude = ('user',)  # Exclude the user field from the inline display

@admin.register(GuestUser)
class GuestUserAdmin(admin.ModelAdmin):
    list_display = ('email', 'phone')
    inlines = [GuestUserOrderInline]

@admin.register(Coupon)
class CouponAdmin(admin.ModelAdmin):
    list_display = ('code', 'discount_amount', 'discount_percent', 'is_active',
                   'valid_from', 'valid_to', 'current_uses', 'max_uses')
    list_filter = ('is_active', 'valid_from', 'valid_to')
    search_fields = ('code', 'description')
    readonly_fields = ('current_uses', 'created_at', 'stripe_coupon_id')
    fieldsets = (
        ('Basic Information', {
            'fields': ('code', 'description', 'is_active')
        }),
        ('Discount', {
            'fields': ('discount_amount', 'discount_percent')
        }),
        ('Validity', {
            'fields': ('valid_from', 'valid_to', 'max_uses', 'current_uses')
        }),
        ('Stripe Information', {
            'fields': ('stripe_coupon_id',),
            'classes': ('collapse',)
        }),
    )

@admin.register(CouponUsage)
class CouponUsageAdmin(admin.ModelAdmin):
    list_display = ('coupon', 'user', 'guest_email', 'order', 'used_at')
    list_filter = ('used_at',)
    search_fields = ('coupon__code', 'user__username', 'user__email', 'guest_email')
    readonly_fields = ('used_at',)
