"""
Django admin configuration for the Moderation application.

This module provides comprehensive admin interfaces for content moderation
including edit submissions, photo submissions, and state transition logs.
Includes a custom moderation admin site for dedicated moderation workflows.

Performance targets:
- List views: < 12 queries
- Change views: < 15 queries
- Page load time: < 500ms for 100 records
"""

from django.contrib import admin, messages
from django.contrib.admin import AdminSite
from django.urls import reverse
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django_fsm_log.models import StateLog

from .models import EditSubmission, PhotoSubmission


class ModerationAdminSite(AdminSite):
    """
    Custom admin site for moderation workflows.

    Provides a dedicated admin interface for moderators with:
    - Dashboard with pending counts
    - Quick action buttons
    - Moderation statistics
    - Activity feed

    Access is restricted to users with MODERATOR, ADMIN, or SUPERUSER roles.
    """

    site_header = "ThrillWiki Moderation"
    site_title = "ThrillWiki Moderation"
    index_title = "Moderation Dashboard"

    def has_permission(self, request):
        """Only allow moderators and above to access this admin site."""
        return request.user.is_authenticated and request.user.role in [
            "MODERATOR",
            "ADMIN",
            "SUPERUSER",
        ]

    def index(self, request, extra_context=None):
        """Add dashboard statistics to the index page."""
        extra_context = extra_context or {}

        # Get pending counts
        extra_context["pending_edits"] = EditSubmission.objects.filter(status="PENDING").count()
        extra_context["pending_photos"] = PhotoSubmission.objects.filter(status="PENDING").count()

        # Get recent activity
        extra_context["recent_edits"] = EditSubmission.objects.select_related("user", "handled_by").order_by(
            "-created_at"
        )[:5]
        extra_context["recent_photos"] = PhotoSubmission.objects.select_related("user", "handled_by").order_by(
            "-created_at"
        )[:5]

        return super().index(request, extra_context)


moderation_site = ModerationAdminSite(name="moderation")


class EditSubmissionAdmin(admin.ModelAdmin):
    """
    Admin interface for edit submission moderation.

    Provides edit submission management with:
    - Bulk approve/reject/escalate actions
    - FSM-aware status handling
    - User and content linking
    - Change preview

    Query optimizations:
    - select_related: user, content_type, handled_by
    """

    list_display = (
        "id",
        "user_link",
        "content_type_display",
        "content_link",
        "status_badge",
        "created_at",
        "handled_by_link",
    )
    list_filter = ("status", "content_type", "created_at")
    list_select_related = ["user", "content_type", "handled_by"]
    search_fields = ("user__username", "reason", "source", "notes", "object_id")
    readonly_fields = (
        "user",
        "content_type",
        "object_id",
        "changes",
        "created_at",
        "changes_preview",
    )
    list_per_page = 50
    show_full_result_count = False
    ordering = ("-created_at",)
    date_hierarchy = "created_at"

    fieldsets = (
        (
            "Submission Details",
            {
                "fields": ("user", "content_type", "object_id"),
                "description": "Who submitted what.",
            },
        ),
        (
            "Proposed Changes",
            {
                "fields": ("changes", "changes_preview"),
                "description": "The changes being proposed.",
            },
        ),
        (
            "Submission Info",
            {
                "fields": ("reason", "source"),
                "classes": ("collapse",),
                "description": "Reason and source for the submission.",
            },
        ),
        (
            "Status",
            {
                "fields": ("status", "handled_by", "notes"),
                "description": "Current status and moderation notes.",
            },
        ),
        (
            "Metadata",
            {
                "fields": ("created_at",),
                "classes": ("collapse",),
            },
        ),
    )

    @admin.display(description="User")
    def user_link(self, obj):
        """Display user as clickable link."""
        if obj.user:
            try:
                url = reverse("admin:accounts_customuser_change", args=[obj.user.id])
                return format_html('<a href="{}">{}</a>', url, obj.user.username)
            except Exception:
                return obj.user.username
        return "-"

    @admin.display(description="Type")
    def content_type_display(self, obj):
        """Display content type in a readable format."""
        if obj.content_type:
            return f"{obj.content_type.app_label}.{obj.content_type.model}"
        return "-"

    @admin.display(description="Content")
    def content_link(self, obj):
        """Display content object as clickable link."""
        try:
            content_obj = obj.content_object
            if content_obj:
                if hasattr(content_obj, "get_absolute_url"):
                    url = content_obj.get_absolute_url()
                    return format_html('<a href="{}">{}</a>', url, str(content_obj)[:30])
                return str(content_obj)[:30]
        except Exception:
            pass
        return format_html('<span style="color: red;">Not found</span>')

    @admin.display(description="Status")
    def status_badge(self, obj):
        """Display status with color-coded badge."""
        colors = {
            "PENDING": "orange",
            "APPROVED": "green",
            "REJECTED": "red",
            "ESCALATED": "purple",
        }
        color = colors.get(obj.status, "gray")
        return format_html(
            '<span style="background-color: {}; color: white; padding: 2px 8px; '
            'border-radius: 4px; font-size: 11px;">{}</span>',
            color,
            obj.status,
        )

    @admin.display(description="Handled By")
    def handled_by_link(self, obj):
        """Display handler as clickable link."""
        if obj.handled_by:
            try:
                url = reverse("admin:accounts_customuser_change", args=[obj.handled_by.id])
                return format_html('<a href="{}">{}</a>', url, obj.handled_by.username)
            except Exception:
                return obj.handled_by.username
        return "-"

    @admin.display(description="Changes Preview")
    def changes_preview(self, obj):
        """Display changes in a formatted preview."""
        if obj.changes:
            html = ['<table style="border-collapse: collapse;">']
            html.append("<tr><th>Field</th><th>Old</th><th>New</th></tr>")
            for field, values in obj.changes.items():
                if isinstance(values, dict):
                    old = values.get("old", "-")
                    new = values.get("new", "-")
                else:
                    old = "-"
                    new = str(values)
                html.append(
                    f'<tr><td style="padding: 4px; border: 1px solid #ddd;">{field}</td>'
                    f'<td style="padding: 4px; border: 1px solid #ddd;">{old}</td>'
                    f'<td style="padding: 4px; border: 1px solid #ddd; color: green;">{new}</td></tr>'
                )
            html.append("</table>")
            return mark_safe("".join(html))
        return "-"

    def save_model(self, request, obj, form, change):
        """Handle FSM transitions on status change."""
        if "status" in form.changed_data:
            try:
                if obj.status == "APPROVED":
                    obj.approve(request.user)
                elif obj.status == "REJECTED":
                    obj.reject(request.user)
                elif obj.status == "ESCALATED":
                    obj.escalate(request.user)
            except Exception as e:
                messages.error(request, f"Status transition failed: {str(e)}")
                return
        super().save_model(request, obj, form, change)

    @admin.action(description="Approve selected submissions")
    def bulk_approve(self, request, queryset):
        """Approve all selected pending submissions."""
        count = 0
        errors = 0
        for submission in queryset.filter(status="PENDING"):
            try:
                submission.approve(request.user)
                count += 1
            except Exception:
                errors += 1
        self.message_user(request, f"Approved {count} submissions.")
        if errors:
            self.message_user(
                request,
                f"Failed to approve {errors} submissions.",
                level=messages.WARNING,
            )

    @admin.action(description="Reject selected submissions")
    def bulk_reject(self, request, queryset):
        """Reject all selected pending submissions."""
        count = 0
        for submission in queryset.filter(status="PENDING"):
            try:
                submission.reject(request.user)
                count += 1
            except Exception:
                pass
        self.message_user(request, f"Rejected {count} submissions.")

    @admin.action(description="Escalate selected submissions")
    def bulk_escalate(self, request, queryset):
        """Escalate all selected pending submissions."""
        count = 0
        for submission in queryset.filter(status="PENDING"):
            try:
                submission.escalate(request.user)
                count += 1
            except Exception:
                pass
        self.message_user(request, f"Escalated {count} submissions.")

    def get_actions(self, request):
        """Add moderation actions."""
        actions = super().get_actions(request)
        actions["bulk_approve"] = (
            self.bulk_approve,
            "bulk_approve",
            "Approve selected submissions",
        )
        actions["bulk_reject"] = (
            self.bulk_reject,
            "bulk_reject",
            "Reject selected submissions",
        )
        actions["bulk_escalate"] = (
            self.bulk_escalate,
            "bulk_escalate",
            "Escalate selected submissions",
        )
        return actions


class PhotoSubmissionAdmin(admin.ModelAdmin):
    """
    Admin interface for photo submission moderation.

    Provides photo submission management with:
    - Image preview in list view
    - Bulk approve/reject actions
    - FSM-aware status handling
    - User and content linking

    Query optimizations:
    - select_related: user, content_type, handled_by
    """

    list_display = (
        "id",
        "user_link",
        "content_type_display",
        "content_link",
        "photo_preview",
        "status_badge",
        "created_at",
        "handled_by_link",
    )
    list_filter = ("status", "content_type", "created_at")
    list_select_related = ["user", "content_type", "handled_by"]
    search_fields = ("user__username", "caption", "notes", "object_id")
    readonly_fields = (
        "user",
        "content_type",
        "object_id",
        "photo_preview",
        "created_at",
    )
    list_per_page = 50
    show_full_result_count = False
    ordering = ("-created_at",)
    date_hierarchy = "created_at"

    fieldsets = (
        (
            "Submission Details",
            {
                "fields": ("user", "content_type", "object_id"),
                "description": "Who submitted what.",
            },
        ),
        (
            "Photo",
            {
                "fields": ("photo", "photo_preview", "caption"),
                "description": "The submitted photo.",
            },
        ),
        (
            "Status",
            {
                "fields": ("status", "handled_by", "notes"),
                "description": "Current status and moderation notes.",
            },
        ),
        (
            "Metadata",
            {
                "fields": ("created_at",),
                "classes": ("collapse",),
            },
        ),
    )

    @admin.display(description="User")
    def user_link(self, obj):
        """Display user as clickable link."""
        if obj.user:
            try:
                url = reverse("admin:accounts_customuser_change", args=[obj.user.id])
                return format_html('<a href="{}">{}</a>', url, obj.user.username)
            except Exception:
                return obj.user.username
        return "-"

    @admin.display(description="Type")
    def content_type_display(self, obj):
        """Display content type in a readable format."""
        if obj.content_type:
            return f"{obj.content_type.app_label}.{obj.content_type.model}"
        return "-"

    @admin.display(description="Content")
    def content_link(self, obj):
        """Display content object as clickable link."""
        try:
            content_obj = obj.content_object
            if content_obj:
                if hasattr(content_obj, "get_absolute_url"):
                    url = content_obj.get_absolute_url()
                    return format_html('<a href="{}">{}</a>', url, str(content_obj)[:30])
                return str(content_obj)[:30]
        except Exception:
            pass
        return format_html('<span style="color: red;">Not found</span>')

    @admin.display(description="Preview")
    def photo_preview(self, obj):
        """Display photo preview thumbnail."""
        if obj.photo:
            return format_html(
                '<img src="{}" style="max-height: 80px; max-width: 150px; '
                'border-radius: 4px; object-fit: cover;" loading="lazy" />',
                obj.photo.url,
            )
        return format_html('<span style="color: gray;">No photo</span>')

    @admin.display(description="Status")
    def status_badge(self, obj):
        """Display status with color-coded badge."""
        colors = {
            "PENDING": "orange",
            "APPROVED": "green",
            "REJECTED": "red",
        }
        color = colors.get(obj.status, "gray")
        return format_html(
            '<span style="background-color: {}; color: white; padding: 2px 8px; '
            'border-radius: 4px; font-size: 11px;">{}</span>',
            color,
            obj.status,
        )

    @admin.display(description="Handled By")
    def handled_by_link(self, obj):
        """Display handler as clickable link."""
        if obj.handled_by:
            try:
                url = reverse("admin:accounts_customuser_change", args=[obj.handled_by.id])
                return format_html('<a href="{}">{}</a>', url, obj.handled_by.username)
            except Exception:
                return obj.handled_by.username
        return "-"

    def save_model(self, request, obj, form, change):
        """Handle FSM transitions on status change."""
        if "status" in form.changed_data:
            try:
                if obj.status == "APPROVED":
                    obj.approve(request.user, obj.notes)
                elif obj.status == "REJECTED":
                    obj.reject(request.user, obj.notes)
            except Exception as e:
                messages.error(request, f"Status transition failed: {str(e)}")
                return
        super().save_model(request, obj, form, change)

    @admin.action(description="Approve selected photos")
    def bulk_approve(self, request, queryset):
        """Approve all selected pending photo submissions."""
        count = 0
        for submission in queryset.filter(status="PENDING"):
            try:
                submission.approve(request.user, "Bulk approved")
                count += 1
            except Exception:
                pass
        self.message_user(request, f"Approved {count} photo submissions.")

    @admin.action(description="Reject selected photos")
    def bulk_reject(self, request, queryset):
        """Reject all selected pending photo submissions."""
        count = 0
        for submission in queryset.filter(status="PENDING"):
            try:
                submission.reject(request.user, "Bulk rejected")
                count += 1
            except Exception:
                pass
        self.message_user(request, f"Rejected {count} photo submissions.")

    def get_actions(self, request):
        """Add moderation actions."""
        actions = super().get_actions(request)
        actions["bulk_approve"] = (
            self.bulk_approve,
            "bulk_approve",
            "Approve selected photos",
        )
        actions["bulk_reject"] = (
            self.bulk_reject,
            "bulk_reject",
            "Reject selected photos",
        )
        return actions


class StateLogAdmin(admin.ModelAdmin):
    """
    Admin interface for FSM state transition logs.

    Read-only admin for viewing state machine transition history.
    Logs are automatically created and should not be modified.

    Query optimizations:
    - select_related: content_type, by
    """

    list_display = (
        "id",
        "timestamp",
        "model_name",
        "object_link",
        "state_badge",
        "transition",
        "user_link",
    )
    list_filter = ("content_type", "state", "transition", "timestamp")
    list_select_related = ["content_type", "by"]
    search_fields = ("state", "transition", "description", "by__username", "object_id")
    readonly_fields = (
        "timestamp",
        "content_type",
        "object_id",
        "state",
        "transition",
        "by",
        "description",
    )
    date_hierarchy = "timestamp"
    ordering = ("-timestamp",)
    list_per_page = 50
    show_full_result_count = False

    fieldsets = (
        (
            "Transition Details",
            {
                "fields": ("state", "transition", "description"),
                "description": "The state transition that occurred.",
            },
        ),
        (
            "Related Object",
            {
                "fields": ("content_type", "object_id"),
                "description": "The object that was transitioned.",
            },
        ),
        (
            "Audit",
            {
                "fields": ("by", "timestamp"),
                "description": "Who performed the transition and when.",
            },
        ),
    )

    @admin.display(description="Model")
    def model_name(self, obj):
        """Display the model name from content type."""
        if obj.content_type:
            return obj.content_type.model
        return "-"

    @admin.display(description="Object")
    def object_link(self, obj):
        """Display object as clickable link."""
        try:
            content_obj = obj.content_object
            if content_obj:
                if hasattr(content_obj, "get_absolute_url"):
                    url = content_obj.get_absolute_url()
                    return format_html('<a href="{}">{}</a>', url, str(content_obj)[:30])
                return str(content_obj)[:30]
        except Exception:
            pass
        return f"ID: {obj.object_id}"

    @admin.display(description="State")
    def state_badge(self, obj):
        """Display state with color-coded badge."""
        colors = {
            "PENDING": "orange",
            "APPROVED": "green",
            "REJECTED": "red",
            "ESCALATED": "purple",
            "operating": "green",
            "closed": "red",
            "sbno": "orange",
        }
        color = colors.get(obj.state, "gray")
        return format_html(
            '<span style="background-color: {}; color: white; padding: 2px 8px; '
            'border-radius: 4px; font-size: 11px;">{}</span>',
            color,
            obj.state,
        )

    @admin.display(description="User")
    def user_link(self, obj):
        """Display user as clickable link."""
        if obj.by:
            try:
                url = reverse("admin:accounts_customuser_change", args=[obj.by.id])
                return format_html('<a href="{}">{}</a>', url, obj.by.username)
            except Exception:
                return obj.by.username
        return "-"

    def has_add_permission(self, request):
        """Disable manual creation of state logs."""
        return False

    def has_change_permission(self, request, obj=None):
        """Disable editing of state logs."""
        return False

    def has_delete_permission(self, request, obj=None):
        """Only superusers can delete logs."""
        return request.user.is_superuser

    @admin.action(description="Export audit trail to CSV")
    def export_audit_trail(self, request, queryset):
        """Export selected state logs for audit reporting."""
        import csv
        from io import StringIO

        from django.http import HttpResponse

        output = StringIO()
        writer = csv.writer(output)
        writer.writerow(["ID", "Timestamp", "Model", "Object ID", "State", "Transition", "User"])

        for log in queryset:
            writer.writerow(
                [
                    log.id,
                    log.timestamp.isoformat(),
                    log.content_type.model if log.content_type else "",
                    log.object_id,
                    log.state,
                    log.transition,
                    log.by.username if log.by else "",
                ]
            )

        response = HttpResponse(output.getvalue(), content_type="text/csv")
        response["Content-Disposition"] = 'attachment; filename="state_log_audit.csv"'
        self.message_user(request, f"Exported {queryset.count()} log entries.")
        return response

    def get_actions(self, request):
        """Add export action."""
        actions = super().get_actions(request)
        actions["export_audit_trail"] = (
            self.export_audit_trail,
            "export_audit_trail",
            "Export audit trail to CSV",
        )
        return actions


class HistoryEventAdmin(admin.ModelAdmin):
    """
    Admin interface for viewing model history events (pghistory).

    Read-only admin for viewing detailed change history.
    Events are automatically created and should not be modified.
    """

    list_display = (
        "pgh_label",
        "pgh_created_at",
        "object_link",
        "context_preview",
    )
    list_filter = ("pgh_label", "pgh_created_at")
    readonly_fields = (
        "pgh_label",
        "pgh_obj_id",
        "pgh_data",
        "pgh_context",
        "pgh_created_at",
    )
    date_hierarchy = "pgh_created_at"
    ordering = ("-pgh_created_at",)
    list_per_page = 50
    show_full_result_count = False

    fieldsets = (
        (
            "Event Information",
            {
                "fields": ("pgh_label", "pgh_created_at"),
                "description": "Event type and timing.",
            },
        ),
        (
            "Related Object",
            {
                "fields": ("pgh_obj_id",),
                "description": "The object this event belongs to.",
            },
        ),
        (
            "Data",
            {
                "fields": ("pgh_data", "pgh_context"),
                "classes": ("collapse",),
                "description": "Detailed data and context at time of event.",
            },
        ),
    )

    @admin.display(description="Object")
    def object_link(self, obj):
        """Display link to the related object."""
        if obj.pgh_obj and hasattr(obj.pgh_obj, "get_absolute_url"):
            url = obj.pgh_obj.get_absolute_url()
            return format_html('<a href="{}">{}</a>', url, str(obj.pgh_obj)[:30])
        return str(obj.pgh_obj or f"ID: {obj.pgh_obj_id}")[:30]

    @admin.display(description="Context")
    def context_preview(self, obj):
        """Display formatted context preview."""
        if not obj.pgh_context:
            return "-"
        html = ['<table style="font-size: 11px;">']
        for key, value in list(obj.pgh_context.items())[:3]:
            html.append(f"<tr><th>{key}</th><td>{value}</td></tr>")
        if len(obj.pgh_context) > 3:
            html.append("<tr><td colspan='2'>...</td></tr>")
        html.append("</table>")
        return mark_safe("".join(html))

    def has_add_permission(self, request):
        """Disable manual creation of history events."""
        return False

    def has_change_permission(self, request, obj=None):
        """Disable editing of history events."""
        return False

    def has_delete_permission(self, request, obj=None):
        """Only superusers can delete events."""
        return request.user.is_superuser


# Register with moderation site only
moderation_site.register(EditSubmission, EditSubmissionAdmin)
moderation_site.register(PhotoSubmission, PhotoSubmissionAdmin)
moderation_site.register(StateLog, StateLogAdmin)

# Note: Concrete pghistory event models would be registered as they are created
# Example: moderation_site.register(DesignerEvent, HistoryEventAdmin)
