from django.contrib import admin, messages
from django.shortcuts import redirect
from django.urls import reverse
from django.utils import timezone
from django.utils.html import format_html

from . import magazine as mag
from .models import (Coupon, CouponRedemption, DigitalAccess, MagazineIssue, NostalgicItem, Order, OrderItem, ProductImage,
                     StorePageContent, WearableHistoryProduct)


@admin.register(StorePageContent)
class StorePageContentAdmin(admin.ModelAdmin):
    fieldsets = (
        ('Shop page', {'fields': ('hero_title', 'hero_description', 'global_delivery_info')}),
        ('Contact buttons', {'fields': ('whatsapp_number', 'messenger_link'),
                             'description': 'WhatsApp also receives digital-magazine payment messages. '
                                            'Leave blank to use the payment number.'}),
        ('Digital magazine payments', {'fields': ('payment_number', 'payment_methods', 'approval_time_text', 'order_email')}),
        ('Magazine page', {'fields': ('magazine_title', 'magazine_intro')}),
        ('SEO — Google titles & descriptions', {'fields': ('shop_meta_title', 'shop_meta_description',
                                                          'magazine_meta_title', 'magazine_meta_description')}),
    )

    def has_add_permission(self, request):
        return not StorePageContent.objects.exists()

    def changelist_view(self, request, extra_context=None):
        obj = StorePageContent.get_solo()
        return redirect(reverse('admin:store_storepagecontent_change', args=[obj.pk]))


class ProductImageInline(admin.TabularInline):
    model = ProductImage
    extra = 1
    verbose_name = 'Extra photo'


class BaseProductAdmin(admin.ModelAdmin):
    list_display_links = ('thumb', 'title')
    list_editable = ('is_featured', 'in_stock', 'is_active')
    search_fields = ('title', 'description', 'sku')
    prepopulated_fields = {'slug': ('title',)}
    inlines = [ProductImageInline]
    save_on_top = True
    list_per_page = 50
    seo_fieldset = ('SEO (optional — good defaults are used when blank)', {
        'fields': ('meta_title', 'meta_description', 'image_alt', 'sku'), 'classes': ('collapse',)})

    @admin.display(description='')
    def thumb(self, obj):
        return format_html('<img src="{}" alt="" style="height:52px;border-radius:3px">', obj.image.url) if obj.image else '—'

    @admin.display(description='Price')
    def price_col(self, obj):
        if obj.current_price < obj.price:
            return format_html('৳{} <s style="color:#999">৳{}</s>', f'{obj.current_price:,.0f}', f'{obj.price:,.0f}')
        return f'৳{obj.price:,.0f}'

    @admin.display(description='View')
    def view_link(self, obj):
        return format_html('<a href="{}" target="_blank" rel="noopener">Open ↗</a>', obj.get_absolute_url()) if obj.pk else ''


@admin.register(MagazineIssue)
class MagazineIssueAdmin(BaseProductAdmin):
    list_display = ('thumb', 'title', 'issue_label', 'editions', 'price_col', 'digital_price', 'pending_readers',
                    'is_featured', 'in_stock', 'is_active', 'view_link')
    list_filter = ('digital_mode', 'print_available', 'is_active', 'in_stock')
    readonly_fields = ('preview_status',)
    inlines = []
    fieldsets = (
        ('Issue', {'fields': ('title', 'slug', 'issue_label', 'subtitle', 'image', 'description', 'contents',
                              'language', 'published_on', 'is_featured', 'is_active'),
                   'description': 'Tip: give a short English slug (e.g. <code>issue-01-lost-professions</code>) '
                                  'for a clean web address.'}),
        ('Print edition', {'fields': ('print_available', 'price', 'discount_price', 'in_stock'),
                           'description': 'Printed copies are ordered through the shop cart (cash on delivery).'}),
        ('Digital edition', {
            'fields': ('digital_mode', 'digital_price', 'pdf_file', 'preview_pages', 'preview_status'),
            'description': '<b>Free</b>: the whole PDF is readable by everyone. '
                           '<b>Paid</b>: only the pages in “Preview pages” are free (e.g. <code>1-3, 8</code>); '
                           'readers unlock the rest after you approve their payment in “Digital magazine access”. '
                           'The full PDF is stored privately.'}),
        BaseProductAdmin.seo_fieldset,
    )

    def get_queryset(self, request):
        from django.db.models import Count, Q
        return super().get_queryset(request).annotate(
            _pending=Count('digital_access', filter=Q(digital_access__status='pending')))

    @admin.display(description='Editions')
    def editions(self, obj):
        return obj.edition_label or '—'

    @admin.display(description='Waiting approval', ordering='_pending')
    def pending_readers(self, obj):
        if not obj._pending:
            return '—'
        url = reverse('admin:store_digitalaccess_changelist') + f'?status__exact=pending&product__id__exact={obj.pk}'
        return format_html('<a href="{}" style="color:#b34a2e;font-weight:700">{} to approve</a>', url, obj._pending)

    @admin.display(description='Reader preview')
    def preview_status(self, obj):
        if not obj.pdf_file:
            return 'Upload a PDF to enable online reading.'
        if obj.digital_mode == 'free':
            return f'Free: all {obj.page_count or "?"} pages are readable.'
        if obj.digital_mode == 'none':
            return 'Digital edition is off (print only).'
        if obj.preview_page_list:
            link = format_html(' <a href="{}" target="_blank">Open preview PDF</a>', obj.preview_pdf.url) if obj.preview_pdf else ''
            return format_html('Free pages: {} of {}.{}', ', '.join(map(str, obj.preview_page_list)), obj.page_count or '?', link)
        return 'No free pages chosen — readers will only see the unlock box.'

    def save_model(self, request, obj, form, change):
        obj.product_type = 'magazine'
        super().save_model(request, obj, form, change)
        if obj.pdf_file and (not change or {'pdf_file', 'preview_pages', 'digital_mode'} & set(form.changed_data)):
            try:
                mag.build_preview(obj)
                messages.success(request, f'PDF read: {obj.page_count} pages. Free pages: '
                                          f'{", ".join(map(str, obj.preview_page_list)) or ("all" if obj.digital_mode == "free" else "none")}.')
            except Exception as exc:
                messages.error(request, f'Could not read the PDF: {exc}')


@admin.register(WearableHistoryProduct)
class WearableHistoryAdmin(BaseProductAdmin):
    list_display = ('thumb', 'title', 'price_col', 'sizes', 'is_featured', 'in_stock', 'is_active', 'view_link')
    list_filter = ('is_active', 'in_stock', 'is_featured')
    fieldsets = (
        ('Product', {'fields': ('title', 'slug', 'image', 'description', 'price', 'discount_price',
                                'sizes', 'colors', 'in_stock', 'is_featured', 'is_active')}),
        BaseProductAdmin.seo_fieldset,
    )

    def save_model(self, request, obj, form, change):
        obj.product_type = 'merch'
        super().save_model(request, obj, form, change)


@admin.register(NostalgicItem)
class NostalgicItemAdmin(BaseProductAdmin):
    list_display = ('thumb', 'title', 'price_col', 'is_featured', 'in_stock', 'is_active', 'view_link')
    list_filter = ('is_active', 'in_stock', 'is_featured')
    fieldsets = (
        ('Item', {'fields': ('title', 'slug', 'image', 'description', 'price', 'discount_price',
                             'in_stock', 'is_featured', 'is_active'),
                  'description': 'Tell the story of the item in the description — where it comes from and why it '
                                 'brings back memories. Readers see it as “Read the story”.'}),
        ('Options (optional)', {'fields': ('sizes', 'colors'), 'classes': ('collapse',)}),
        BaseProductAdmin.seo_fieldset,
    )

    def save_model(self, request, obj, form, change):
        obj.product_type = 'nostalgic'
        super().save_model(request, obj, form, change)


@admin.register(DigitalAccess)
class DigitalAccessAdmin(admin.ModelAdmin):
    list_display = ('reference', 'status_badge', 'name', 'phone', 'account', 'sender_number', 'trx_id', 'amount',
                    'product', 'created_at', 'open_count')
    list_filter = ('status', 'product', 'created_at')
    search_fields = ('reference', 'trx_id', 'name', 'phone', 'sender_number')
    readonly_fields = ('reference', 'product', 'name', 'phone', 'sender_number', 'trx_id', 'amount',
                       'coupon', 'discount_amount', 'created_at', 'reviewed_at', 'open_count')
    raw_id_fields = ('user',)
    fields = ('reference', 'status', 'product', 'amount', 'coupon', 'discount_amount', 'name', 'phone', 'user', 'sender_number', 'trx_id',
              'admin_note', 'created_at', 'reviewed_at', 'open_count')
    actions = ('approve_selected', 'reject_selected', 'revoke_selected')
    date_hierarchy = 'created_at'

    def has_add_permission(self, request):
        return False

    @admin.display(description='Account', ordering='user__email')
    def account(self, obj):
        return obj.user.email if obj.user_id else 'guest'

    @admin.display(description='Status', ordering='status')
    def status_badge(self, obj):
        colors = {'pending': '#c9952a', 'approved': '#2e7d32', 'rejected': '#b34a2e', 'revoked': '#666'}
        return format_html('<span style="background:{};color:#fff;padding:3px 8px;border-radius:10px;'
                           'font-size:11px;font-weight:600">{}</span>', colors.get(obj.status), obj.get_status_display())

    def save_model(self, request, obj, form, change):
        if 'status' in form.changed_data and obj.status != 'pending':
            obj.reviewed_at = timezone.now()
        super().save_model(request, obj, form, change)

    @admin.action(description='✅ Approve — payment received (reader can read the full issue)')
    def approve_selected(self, request, queryset):
        n = 0
        for access in queryset.exclude(status='approved'):
            mag.approve(access)
            n += 1
        self.message_user(request, f'{n} reader(s) approved. Their browser unlocks the full magazine automatically.',
                          messages.SUCCESS)

    @admin.action(description='❌ Reject — payment not found')
    def reject_selected(self, request, queryset):
        n = queryset.filter(status='pending').update(status='rejected', reviewed_at=timezone.now())
        self.message_user(request, f'{n} request(s) rejected.', messages.WARNING)

    @admin.action(description='🚫 Revoke reading access')
    def revoke_selected(self, request, queryset):
        n = queryset.filter(status='approved').update(status='revoked', reviewed_at=timezone.now())
        self.message_user(request, f'{n} reader(s) lost access.', messages.WARNING)


class CouponRedemptionInline(admin.TabularInline):
    model = CouponRedemption
    extra = 0
    can_delete = False
    fields = ('created_at', 'amount', 'user', 'phone', 'order', 'digital_access')
    readonly_fields = fields

    def has_add_permission(self, request, obj=None):
        return False


@admin.register(Coupon)
class CouponAdmin(admin.ModelAdmin):
    list_display = ('code', 'deal', 'applies_to', 'usage', 'per_customer_limit', 'valid_to', 'owner', 'source', 'is_active')
    list_filter = ('is_active', 'discount_type', 'applies_to', 'source', 'requires_login')
    search_fields = ('code', 'note', 'owner__email', 'owner__username')
    filter_horizontal = ('products',)
    raw_id_fields = ('owner',)
    readonly_fields = ('current_uses', 'source', 'created_at')
    inlines = [CouponRedemptionInline]
    fieldsets = (
        (None, {'fields': ('code', 'note', 'is_active')}),
        ('Discount', {'fields': ('discount_type', 'discount_value', 'max_discount', 'min_order_amount'),
                      'description': 'Percentage or fixed taka. For percentage you can cap the taka amount.'}),
        ('What it works on', {'fields': ('applies_to', 'products')}),
        ('How many times', {'fields': ('max_uses', 'per_customer_limit', 'current_uses'),
                            'description': 'Leave a limit empty for unlimited. Per-customer uses are counted by account and phone number.'}),
        ('When and who', {'fields': ('valid_from', 'valid_to', 'requires_login', 'owner', 'source', 'created_at')}),
    )

    @admin.display(description='Discount')
    def deal(self, obj):
        text = f"{obj.discount_value:.0f}%" if obj.discount_type == 'percentage' else f"৳{obj.discount_value:.0f}"
        if obj.max_discount is not None and obj.discount_type == 'percentage':
            text += f" (max ৳{obj.max_discount:.0f})"
        if obj.min_order_amount:
            text += f" · min ৳{obj.min_order_amount:.0f}"
        return text

    @admin.display(description='Used')
    def usage(self, obj):
        return f"{obj.current_uses} / {'∞' if obj.max_uses is None else obj.max_uses}"


@admin.register(CouponRedemption)
class CouponRedemptionAdmin(admin.ModelAdmin):
    list_display = ('coupon', 'amount', 'user', 'phone', 'order', 'digital_access', 'created_at')
    list_filter = ('coupon__source',)
    search_fields = ('coupon__code', 'phone', 'user__email')
    raw_id_fields = ('coupon', 'user', 'order', 'digital_access')

    def has_add_permission(self, request):
        return False


class OrderItemInline(admin.TabularInline):
    model = OrderItem
    extra = 0
    readonly_fields = ('product', 'size', 'color', 'quantity', 'price')


@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'phone', 'district', 'customer', 'total_amount', 'status', 'created_at')
    list_editable = ('status',)
    raw_id_fields = ('user',)
    fieldsets = (
        ('Status & tracking', {'fields': ('status', 'courier', 'tracking_code', 'customer_message'),
                               'description': 'Changing the status updates the tracking timeline the customer sees in their account.'}),
        ('Customer', {'fields': ('user', 'name', 'phone', 'alt_phone')}),
        ('Delivery address', {'fields': ('division', 'district', 'area', 'address_line', 'location', 'note')}),
        ('Money', {'fields': ('coupon', 'discount_amount', 'total_amount')}),
        ('Timeline', {'fields': ('created_at', 'confirmed_at', 'shipped_at', 'delivered_at', 'cancelled_at'),
                      'classes': ('collapse',)}),
    )

    @admin.display(description='Account', ordering='user__email')
    def customer(self, obj):
        return obj.user.email if obj.user_id else 'guest'
    list_filter = ('status', 'division', 'created_at')
    search_fields = ('name', 'phone', 'alt_phone', 'location', 'tracking_code', 'id')
    inlines = [OrderItemInline]
    readonly_fields = ('total_amount', 'discount_amount', 'coupon', 'created_at', 'confirmed_at', 'shipped_at',
                       'delivered_at', 'cancelled_at')
