from django.contrib import admin
from django.utils.html import format_html
from django.db.models import Sum
from django import forms
from django.urls import path, reverse
from django.shortcuts import redirect
from unfold.admin import ModelAdmin, TabularInline
from unfold.decorators import display
from .models import ESP32Config, Order, Salesperson, WeChatPayConfig, Service, VCCourse, ProductFeature, CommissionLog, WeChatUser, Distributor, Withdrawal, ServiceOrder, CourseEnrollment, AdminPhoneNumber
from .admin_actions import export_to_csv, export_to_excel
import qrcode
from io import BytesIO
import base64

# 自定义后台标题1
admin.site.site_header = "量迹AI科技硬件/服务商场后台"
admin.site.site_title = "量迹AI后台"
admin.site.index_title = "欢迎使用量迹AI管理系统"

class OrderableAdminMixin:
    """
    为 Admin 添加排序功能的 Mixin
    提供上移、下移按钮，直接交换 order 值
    """
    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path('<path:object_id>/move-up/', self.admin_site.admin_view(self.move_up_view), name=f'{self.model._meta.app_label}_{self.model._meta.model_name}_move_up'),
            path('<path:object_id>/move-down/', self.admin_site.admin_view(self.move_down_view), name=f'{self.model._meta.app_label}_{self.model._meta.model_name}_move_down'),
        ]
        return custom_urls + urls

    def move_up_view(self, request, object_id):
        obj = self.get_object(request, object_id)
        if obj:
            # 找到排在它前面的一个 (order 小于它的最大值)
            prev_obj = self.model.objects.filter(order__lt=obj.order).order_by('-order').first()
            if prev_obj:
                # 交换
                obj.order, prev_obj.order = prev_obj.order, obj.order
                obj.save()
                prev_obj.save()
                self.message_user(request, f"成功将 {obj} 上移")
            else:
                # 已经是第一个，或者前面没有更小的 order
                # 尝试查找 order 等于它的其他对象（理论上不应发生，但为了稳健）
                pass
        return redirect(request.META.get('HTTP_REFERER', '..'))

    def move_down_view(self, request, object_id):
        obj = self.get_object(request, object_id)
        if obj:
            # 找到排在它后面的一个 (order 大于它的最小值)
            next_obj = self.model.objects.filter(order__gt=obj.order).order_by('order').first()
            if next_obj:
                # 交换
                obj.order, next_obj.order = next_obj.order, obj.order
                obj.save()
                next_obj.save()
                self.message_user(request, f"成功将 {obj} 下移")
        return redirect(request.META.get('HTTP_REFERER', '..'))

    def order_actions(self, obj):
        # 只有专家用户才显示排序按钮
        if not getattr(obj, 'is_star', True): # 默认为True是为了兼容其他模型，WeChatUser有is_star字段
            return "默认排序"

        # 使用 inline style 实现基本样式，hover 效果如果不能用 CSS 文件，就只能妥协或者用 onmouseover
        btn_style = (
            "display: inline-flex; align-items: center; justify-content: center; "
            "width: 26px; height: 26px; border-radius: 6px; "
            "background-color: #f3f4f6; color: #4b5563; text-decoration: none; "
            "border: 1px solid #e5e7eb; transition: all 0.2s;"
        )
        # onmouseover js
        hover_js = "this.style.backgroundColor='#dbeafe'; this.style.color='#2563eb'; this.style.borderColor='#bfdbfe';"
        out_js = "this.style.backgroundColor='#f3f4f6'; this.style.color='#4b5563'; this.style.borderColor='#e5e7eb';"

        return format_html(
            '<div style="display: flex; align-items: center; gap: 6px;">'
            '<a href="{}" title="上移" style="{}" onmouseover="{}" onmouseout="{}">'
            '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 15l-6-6-6 6"/></svg>'
            '</a>'
            '<span style="font-weight: 700; font-family: system-ui, -apple-system, sans-serif; min-width: 20px; text-align: center; color: #374151; font-size: 13px;">{}</span>'
            '<a href="{}" title="下移" style="{}" onmouseover="{}" onmouseout="{}">'
            '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>'
            '</a>'
            '</div>',
            reverse(f'admin:{self.model._meta.app_label}_{self.model._meta.model_name}_move_up', args=[obj.pk]),
            btn_style, hover_js, out_js,
            obj.order,
            reverse(f'admin:{self.model._meta.app_label}_{self.model._meta.model_name}_move_down', args=[obj.pk]),
            btn_style, hover_js, out_js,
        )
    order_actions.short_description = "排序调节"
    order_actions.allow_tags = True


class ExternalUploadWidget(forms.URLInput):
    def __init__(self, upload_url, accept='*', *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.upload_url = upload_url
        self.attrs.update({
            'class': 'upload-url-input vTextField',
            'data-upload-url': upload_url,
            'data-accept': accept,
            'placeholder': '上传文件后自动生成URL',
            'style': 'width: 100%;'
        })

    class Media:
        js = ('shop/js/admin_upload.js',)
        css = {
            'all': ('shop/css/admin_upload.css',)
        }

class ESP32ConfigAdminForm(forms.ModelForm):
    class Meta:
        model = ESP32Config
        fields = '__all__'
        widgets = {
            'static_image_url': ExternalUploadWidget(
                upload_url='https://data.tangledup-ai.com/upload?folder=market_page%2Fhardware_xiaozhi%2Fproduct_static_image',
                accept='image/*'
            ),
            'model_3d_url': ExternalUploadWidget(
                upload_url='https://data.tangledup-ai.com/upload?folder=market_page%2Fhardware_xiaozhi%2Fproduct_3D_image',
                accept='.zip'
            ),
        }

class ProductFeatureInline(TabularInline):
    model = ProductFeature
    extra = 1
    fields = ('title', 'description', 'icon_name', 'icon_image', 'icon_url', 'order')

@admin.register(WeChatPayConfig)
class WeChatPayConfigAdmin(ModelAdmin):
    list_display = ('app_id', 'mch_id', 'is_active', 'notify_url', 'updated_at_display')
    list_filter = ('is_active',)
    search_fields = ('app_id', 'mch_id')
    
    def updated_at_display(self, obj):
        # 假设模型没有 updated_at，如果有可以显示，这里仅作占位或移除
        return "N/A"
    updated_at_display.short_description = "更新时间"

    fieldsets = (
        ('核心配置 (登录与支付)', {
            'fields': ('app_id', 'app_secret', 'mch_id', 'is_active'),
            'description': 'AppID 和 AppSecret 是小程序登录和支付的基础凭证。请确保 AppID 与小程序后台一致 (项目中优先使用 wxdf2ca73e6c0929f0)。'
        }),
        ('微信支付 V3 安全配置 (推荐)', {
            'fields': ('apiv3_key', 'mch_cert_serial_no', 'mch_private_key'),
            'description': '使用 Native 支付必须配置这些项。私钥可以粘贴在这里，或者放在 backend/certs/apiclient_key.pem 文件中。'
        }),
        ('微信支付 V2 安全配置 (旧版)', {
            'fields': ('api_key',),
            'classes': ('collapse',),
            'description': '仅旧版支付接口需要 API Key (V2)。'
        }),
        ('回调配置', {
            'fields': ('notify_url',)
        }),
    )

@admin.register(ESP32Config)
class ESP32ConfigAdmin(OrderableAdminMixin, ModelAdmin):
    form = ESP32ConfigAdminForm
    list_display = ('name', 'chip_type', 'price', 'stock', 'has_camera', 'has_microphone', 'order_actions')
    list_filter = ('chip_type', 'has_camera')
    search_fields = ('name', 'description')
    inlines = [ProductFeatureInline]
    fieldsets = (
        ('基本信息', {
            'fields': ('name', 'price', 'stock', 'commission_rate', 'description')
        }),
        ('硬件参数', {
            'fields': ('chip_type', 'flash_size', 'ram_size', 'has_camera', 'has_microphone')
        }),
        ('详情页图片', {
            'fields': ('detail_image', 'detail_image_url'),
            'description': '图片上传和URL二选一，优先使用URL'
        }),
        ('多媒体资源', {
            'fields': ('static_image_url', 'model_3d_url'),
            'description': '产品静态图和3D模型的外部链接'
        }),
    )

@admin.register(Service)
class ServiceAdmin(OrderableAdminMixin, ModelAdmin):
    list_display = ('title', 'created_at', 'order_actions')
    search_fields = ('title', 'description')
    fieldsets = (
        ('基本信息', {
            'fields': ('title', 'description', 'color')
        }),
        ('价格与交付', {
            'fields': ('price', 'unit', 'delivery_time', 'delivery_content')
        }),
        ('图标', {
            'fields': ('icon', 'icon_url'),
            'description': '图标上传和URL二选一，优先使用URL'
        }),
        ('详情页图片', {
            'fields': ('detail_image', 'detail_image_url'),
            'description': '图片上传和URL二选一，优先使用URL'
        }),
        ('详细内容', {
            'fields': ('features',)
        }),
    )

@admin.register(ServiceOrder)
class ServiceOrderAdmin(ModelAdmin):
    list_display = ('id', 'customer_name', 'service', 'total_price', 'status', 'salesperson', 'created_at')
    list_filter = ('status', 'service', 'salesperson', 'created_at')
    search_fields = ('id', 'customer_name', 'phone_number', 'email')
    readonly_fields = ('total_price', 'created_at', 'updated_at')
    
    fieldsets = (
        ('订单信息', {
            'fields': ('service', 'status', 'total_price', 'created_at')
        }),
        ('客户信息', {
            'fields': ('customer_name', 'company_name', 'phone_number', 'email', 'requirements')
        }),
        ('销售归属', {
            'fields': ('salesperson',)
        }),
    )

@admin.register(VCCourse)
class VCCourseAdmin(OrderableAdminMixin, ModelAdmin):
    list_display = ('title', 'course_type', 'is_video_course', 'price', 'tag', 'instructor', 'lesson_count', 'duration', 'created_at', 'order_actions')
    search_fields = ('title', 'description', 'instructor', 'tag')
    list_filter = ('course_type', 'is_video_course', 'instructor', 'tag')
    actions = ['reset_ordering']

    @admin.action(description="重置排序 (按ID顺序)")
    def reset_ordering(self, request, queryset):
        """
        将选中的课程（或全部）按ID顺序重新分配order值
        """
        # 如果没有选中任何项，默认处理所有（Django Admin默认行为是选中了才会触发Action，但为了稳健）
        # 这里既然是Action，用户必须选中。建议用户选中所有。
        # 为了方便，如果用户只选了一个，我们可以提示他选更多，或者我们其实可以忽略queryset，直接重置所有？
        # 通常Action是针对queryset的。
        # 更好的做法：对选中的queryset按ID排序，然后更新order。
        
        # 这种实现方式：只重置选中的部分，可能会导致order冲突。
        # 稳妥方式：重置整个表的排序。
        
        all_objects = VCCourse.objects.all().order_by('id')
        for index, obj in enumerate(all_objects, start=1):
            obj.order = index
            obj.save(update_fields=['order'])
        
        self.message_user(request, f"成功重置了 {all_objects.count()} 个课程的排序权重。")

    fieldsets = (
        ('基本信息', {
            'fields': ('title', 'description', 'course_type', 'tag', 'price')
        }),
        ('视频设置', {
            'fields': ('is_video_course', 'video_url', 'video_embed_code'),
            'description': '设置是否为视频课程及视频链接'
        }),
        ('课程安排', {
            'fields': ('is_fixed_schedule', 'start_time', 'end_time'),
            'description': '勾选“是否固定时间课程”后，请设置开始和结束时间'
        }),
        ('讲师信息', {
            'fields': ('instructor', 'instructor_title', 'instructor_desc', 'instructor_avatar', 'instructor_avatar_url'),
            'description': '讲师头像上传和URL二选一，优先使用URL'
        }),
        ('课程详情', {
            'fields': ('duration', 'lesson_count', 'content')
        }),
        ('封面', {
            'fields': ('cover_image', 'cover_image_url'),
            'description': '图片上传和URL二选一，优先使用URL'
        }),
        ('详情页长图', {
            'fields': ('detail_image', 'detail_image_url'),
            'description': '图片上传和URL二选一，优先使用URL'
        }),
    )

@admin.register(CourseEnrollment)
class CourseEnrollmentAdmin(ModelAdmin):
    list_display = ('customer_name', 'course', 'phone_number', 'status', 'created_at')
    list_filter = ('status', 'course', 'created_at')
    search_fields = ('customer_name', 'phone_number', 'wechat_id')
    
    fieldsets = (
        ('报名信息', {
            'fields': ('course', 'status', 'created_at')
        }),
        ('客户资料', {
            'fields': ('customer_name', 'phone_number', 'wechat_id', 'email', 'message')
        }),
        ('销售归属', {
            'fields': ('salesperson', 'distributor')
        }),
    )

@admin.register(Salesperson)
class SalespersonAdmin(ModelAdmin):
    list_display = ('name', 'code', 'total_sales', 'view_promotion_url')
    search_fields = ('name', 'code')
    readonly_fields = ('promotion_qr_code', 'promotion_url_display', 'total_sales_display')

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        queryset = queryset.annotate(
            _total_sales=Sum('orders__total_price', default=0)
        )
        return queryset

    @display(description="累计销售额 (已支付)", ordering='_total_sales')
    def total_sales(self, obj):
        # 仅计算已支付的订单
        paid_sales = obj.orders.filter(status='paid').aggregate(total=Sum('total_price'))['total']
        return f"¥{paid_sales or 0:.2f}"

    def total_sales_display(self, obj):
        return self.total_sales(obj)
    total_sales_display.short_description = "累计销售额 (已支付)"

    def promotion_url(self, obj):
        # 生产环境配置
        base_url = "https://market.quant-speed.com" 
        return f"{base_url}/?ref={obj.code}"

    @display(description="推广链接")
    def view_promotion_url(self, obj):
        url = self.promotion_url(obj)
        return format_html('<a href="{}" target="_blank" class="button">打开推广链接</a>', url)

    def promotion_url_display(self, obj):
        return self.promotion_url(obj)
    promotion_url_display.short_description = "完整推广链接"

    @display(description="推广二维码")
    def promotion_qr_code(self, obj):
        if not obj.code:
            return "请先保存以生成二维码"
        
        url = self.promotion_url(obj)
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=4,
        )
        qr.add_data(url)
        qr.make(fit=True)

        img = qr.make_image(fill_color="black", back_color="white")
        buffer = BytesIO()
        img.save(buffer, format="PNG")
        img_str = base64.b64encode(buffer.getvalue()).decode()
        
        return format_html('<img src="data:image/png;base64,{}" width="200" height="200" class="qr-code" />', img_str)

    fieldsets = (
        ('基本信息', {
            'fields': ('name', 'code')
        }),
        ('推广工具', {
            'fields': ('promotion_url_display', 'promotion_qr_code')
        }),
        ('业绩统计', {
            'fields': ('total_sales_display',)
        }),
        ('分销设置', {
            'fields': ('parent', 'commission_rate', 'second_level_rate'),
            'description': '设置上级分销员及各级分润比例'
        }),
    )

@admin.register(CommissionLog)
class CommissionLogAdmin(ModelAdmin):
    list_display = ('id', 'salesperson', 'distributor', 'amount', 'level', 'status', 'created_at')
    list_filter = ('status', 'level', 'salesperson', 'distributor', 'created_at')
    search_fields = ('salesperson__name', 'distributor__user__nickname', 'order__id')
    readonly_fields = ('amount', 'level', 'created_at')
    
    fieldsets = (
        ('基本信息', {
            'fields': ('salesperson', 'distributor', 'order', 'amount', 'level')
        }),
        ('状态管理', {
            'fields': ('status', 'created_at')
        }),
    )

class GenderFilter(admin.SimpleListFilter):
    title = '性别'
    parameter_name = 'gender'

    def lookups(self, request, model_admin):
        return (
            (1, '男'),
            (2, '女'),
            (0, '未知'),
        )

    def queryset(self, request, queryset):
        if self.value():
            return queryset.filter(gender=self.value())
        return queryset

class UserSourceFilter(admin.SimpleListFilter):
    title = '用户来源'
    parameter_name = 'user_source'

    def lookups(self, request, model_admin):
        return (
            ('miniprogram', '仅小程序用户'),
            ('both', '网页小程序都已注册'),
        )

    def queryset(self, request, queryset):
        if self.value() == 'miniprogram':
            return queryset.filter(user__isnull=True)
        if self.value() == 'both':
            return queryset.filter(user__isnull=False)
        return queryset

class PriceRangeFilter(admin.SimpleListFilter):
    title = '价格区间'
    parameter_name = 'price_range'

    def lookups(self, request, model_admin):
        return (
            ('0-50', '¥0 - ¥50'),
            ('50-100', '¥50 - ¥100'),
            ('100-500', '¥100 - ¥500'),
            ('500-1000', '¥500 - ¥1000'),
            ('1000+', '¥1000以上'),
        )

    def queryset(self, request, queryset):
        value = self.value()
        if value == '0-50':
            return queryset.filter(total_price__gte=0, total_price__lte=50)
        elif value == '50-100':
            return queryset.filter(total_price__gt=50, total_price__lte=100)
        elif value == '100-500':
            return queryset.filter(total_price__gt=100, total_price__lte=500)
        elif value == '500-1000':
            return queryset.filter(total_price__gt=500, total_price__lte=1000)
        elif value == '1000+':
            return queryset.filter(total_price__gt=1000)
        return queryset

class ProductTypeFilter(admin.SimpleListFilter):
    title = '商品类型'
    parameter_name = 'product_type'

    def lookups(self, request, model_admin):
        return (
            ('hardware', '硬件产品'),
            ('course', '课程'),
            ('activity', '活动'),
        )

    def queryset(self, request, queryset):
        value = self.value()
        if value == 'hardware':
            return queryset.filter(config__isnull=False)
        elif value == 'course':
            return queryset.filter(course__isnull=False)
        elif value == 'activity':
            return queryset.filter(activity__isnull=False)
        return queryset

@admin.register(Order)
class OrderAdmin(ModelAdmin):
    list_display = ('id', 'customer_name', 'get_item_name', 'total_price', 'status', 'salesperson', 'distributor', 'created_at')
    list_filter = ('status', ProductTypeFilter, 'config', 'course', 'activity', PriceRangeFilter, 'salesperson', 'distributor', 'created_at')
    search_fields = ('id', 'customer_name', 'phone_number', 'wechat_trade_no')
    readonly_fields = ('total_price', 'created_at', 'wechat_trade_no')
    actions = [export_to_csv, export_to_excel]
    
    def get_item_name(self, obj):
        if obj.config:
            return f"[硬件] {obj.config.name}"
        if obj.course:
            return f"[课程] {obj.course.title}"
        if obj.activity:
            return f"[活动] {obj.activity.title}"
        return "未知商品"
    get_item_name.short_description = "购买商品"

    fieldsets = (
        ('订单信息', {
            'fields': ('config', 'course', 'activity', 'quantity', 'total_price', 'status', 'created_at')
        }),
        ('客户信息', {
            'fields': ('customer_name', 'phone_number', 'shipping_address', 'wechat_user')
        }),
        ('物流信息', {
            'fields': ('courier_name', 'tracking_number')
        }),
        ('销售归属', {
            'fields': ('salesperson', 'distributor')
        }),
        ('支付信息', {
            'fields': ('wechat_trade_no',)
        }),
    )

@admin.register(WeChatUser)
class WeChatUserAdmin(OrderableAdminMixin, ModelAdmin):
    list_display = ('nickname', 'phone_number', 'is_star', 'title', 'avatar_display', 'gender_display', 'province', 'city', 'created_at', 'order_actions')
    search_fields = ('nickname', 'openid', 'phone_number')
    list_filter = ('is_star', GenderFilter, UserSourceFilter, 'province', 'city', 'created_at')
    readonly_fields = ('openid', 'unionid', 'session_key', 'created_at', 'updated_at')
    actions = [export_to_csv, export_to_excel]

    def avatar_display(self, obj):
        if obj.avatar_url:
            return format_html('<img src="{}" width="50" height="50" style="border-radius: 50%;" />', obj.avatar_url)
        return "暂无"
    avatar_display.short_description = "头像"

    def gender_display(self, obj):
        choices = {0: '未知', 1: '男', 2: '女'}
        return choices.get(obj.gender, '未知')
    gender_display.short_description = "性别"

    def get_fieldsets(self, request, obj=None):
        fieldsets = [
            ('基本信息', {
                'fields': ('user', 'nickname', 'phone_number', 'avatar_url', 'gender')
            }),
        ]

        if obj and obj.is_star:
            fieldsets.append(('专家认证', {
                'fields': ('is_star', 'title', 'skills', 'order'),
                'description': '标记为明星技术用户/专家，将在社区中展示'
            }))
        else:
            fieldsets.append(('专家认证', {
                'fields': ('is_star',),
                'description': '标记为明星技术用户/专家，将在社区中展示。保存后若为专家用户，可进一步编辑专家信息。'
            }))

        fieldsets.append(('位置信息', {
            'fields': ('country', 'province', 'city')
        }))
        
        fieldsets.append(('认证信息', {
            'fields': ('openid', 'unionid', 'session_key'),
            'classes': ('collapse',)
        }))
        
        fieldsets.append(('时间信息', {
            'fields': ('created_at', 'updated_at')
        }))
        
        return fieldsets

@admin.register(Distributor)
class DistributorAdmin(ModelAdmin):
    list_display = ('get_nickname', 'level', 'status', 'total_earnings', 'withdrawable_balance', 'invite_code', 'created_at')
    search_fields = ('user__nickname', 'invite_code')
    list_filter = ('status', 'level', 'created_at')
    readonly_fields = ('total_earnings', 'withdrawable_balance', 'qr_code_url', 'created_at', 'updated_at')
    autocomplete_fields = ['user', 'parent']

    def get_nickname(self, obj):
        return obj.user.nickname
    get_nickname.short_description = "微信昵称"
    get_nickname.admin_order_field = 'user__nickname'

    fieldsets = (
        ('分销员信息', {
            'fields': ('user', 'parent', 'level', 'status')
        }),
        ('收益概览', {
            'fields': ('commission_rate', 'total_earnings', 'withdrawable_balance')
        }),
        ('推广信息', {
            'fields': ('invite_code', 'qr_code_url')
        }),
        ('时间信息', {
            'fields': ('created_at', 'updated_at')
        }),
    )

@admin.register(Withdrawal)
class WithdrawalAdmin(ModelAdmin):
    list_display = ('get_distributor', 'amount', 'status', 'created_at')
    list_filter = ('status', 'created_at')
    search_fields = ('distributor__user__nickname',)
    
    def get_distributor(self, obj):
        return obj.distributor.user.nickname
    get_distributor.short_description = "分销员"

    fieldsets = (
        ('提现详情', {
            'fields': ('distributor', 'amount', 'status', 'remark')
        }),
        ('时间信息', {
            'fields': ('created_at', 'updated_at')
        }),
    )

@admin.register(AdminPhoneNumber)
class AdminPhoneNumberAdmin(ModelAdmin):
    list_display = ('name', 'phone_number', 'is_active', 'created_at')
    list_filter = ('is_active',)
    search_fields = ('name', 'phone_number')
