from django import forms
from django.contrib.admin.views.decorators import staff_member_required
from django.urls import path
from django.urls import reverse
from django.utils.translation import gettext as _
from django.shortcuts import redirect
from django.shortcuts import render
from wagtail import hooks
from wagtail.admin.menu import MenuItem
from wagtail.admin.panels import FieldPanel
from wagtail.admin.ui.tables import Column
from wagtail.admin.widgets import Button
from wagtail.permission_policies import ModelPermissionPolicy
from wagtail.snippets.models import register_snippet
from wagtail.snippets.views.snippets import CreateView, SnippetViewSet, SnippetViewSetGroup

from .forms import (
    NewsletterCampaignAdminForm,
    NewsletterCampaignEditorWidget,
    NewsletterHtmlEditorWidget,
    NewsletterTemplateAdminForm,
)
from .models import (
    ContactFormSubmission,
    NewsletterCampaign,
    NewsletterDispatchRecord,
    NewsletterSystemSettings,
    NewsletterTemplate,
)

SEND_NEWSLETTER_PERMISSION = "base.send_newslettercampaign"


def _contact_status_value(submission):
    return submission.get_processing_status_display()


def _contact_spam_category_value(submission):
    if submission.spam_category is None:
        return "尚未檢查"
    return submission.get_spam_category_display()


def _contact_category_value(submission):
    return submission.get_category_display()


def _newsletter_campaign_add_url() -> str:
    candidates = [
        "wagtailsnippets_base_newslettercampaign:add",
        "base_newslettercampaign:add",
    ]
    for name in candidates:
        try:
            return reverse(name)
        except Exception:
            continue
    return "/admin/snippets/base/newslettercampaign/add/"


@staff_member_required
def newsletter_campaign_type_select_view(request):
    return render(
        request,
        "base/wagtail/newsletter_campaign_type_select.html",
        {
            "title": _("Choose Newsletter Type"),
            "add_url": _newsletter_campaign_add_url(),
            "type_general": NewsletterCampaign.TYPE_GENERAL,
            "type_weekly_news": NewsletterCampaign.TYPE_WEEKLY_NEWS,
        },
    )


@staff_member_required
def newsletter_campaign_add_by_type_view(request, campaign_type: str):
    campaign_type = (campaign_type or "").strip()
    allowed = {NewsletterCampaign.TYPE_GENERAL, NewsletterCampaign.TYPE_WEEKLY_NEWS}
    if campaign_type not in allowed:
        return redirect("newsletter_campaign_type_select")
    return redirect(f"{_newsletter_campaign_add_url()}?campaign_type={campaign_type}")


@hooks.register("register_admin_urls")
def register_newsletter_admin_urls():
    return [
        path(
            "newsletter/campaigns/type-select/",
            newsletter_campaign_type_select_view,
            name="newsletter_campaign_type_select",
        ),
        path(
            "newsletter/campaigns/add/<slug:campaign_type>/",
            newsletter_campaign_add_by_type_view,
            name="newsletter_campaign_add_by_type",
        ),
    ]


class NewsletterCampaignCreateView(CreateView):
    def _resolve_campaign_type(self):
        candidate = (
            self.request.POST.get("campaign_type")
            or self.request.GET.get("campaign_type")
            or ""
        ).strip()
        if candidate in {NewsletterCampaign.TYPE_GENERAL, NewsletterCampaign.TYPE_WEEKLY_NEWS}:
            return candidate
        return ""

    def get(self, request, *args, **kwargs):
        campaign_type = self._resolve_campaign_type()
        if campaign_type in {NewsletterCampaign.TYPE_GENERAL, NewsletterCampaign.TYPE_WEEKLY_NEWS}:
            return super().get(request, *args, **kwargs)
        return redirect("newsletter_campaign_type_select")

    def post(self, request, *args, **kwargs):
        campaign_type = self._resolve_campaign_type()
        if campaign_type not in {NewsletterCampaign.TYPE_GENERAL, NewsletterCampaign.TYPE_WEEKLY_NEWS}:
            # Do not redirect on POST; inject a safe default so form validation can run.
            post_data = request.POST.copy()
            is_weekly_hint = bool(post_data.getlist("weekly_articles")) or bool(
                (post_data.get("item_template_html") or "").strip()
            )
            post_data["campaign_type"] = (
                NewsletterCampaign.TYPE_WEEKLY_NEWS if is_weekly_hint else NewsletterCampaign.TYPE_GENERAL
            )
            request.POST = post_data
        return super().post(request, *args, **kwargs)

    def get_initial(self):
        initial = super().get_initial()
        campaign_type = self._resolve_campaign_type()
        if campaign_type in {NewsletterCampaign.TYPE_GENERAL, NewsletterCampaign.TYPE_WEEKLY_NEWS}:
            initial["campaign_type"] = campaign_type
        if (initial.get("list_id") or "").strip():
            return self._with_default_template(initial)
        default_list_id = (NewsletterSystemSettings.load().member_center_list_id or "").strip()
        if default_list_id:
            initial["list_id"] = default_list_id
        return self._with_default_template(initial)

    def _with_default_template(self, initial: dict):
        if initial.get("newsletter_template"):
            return initial
        campaign_type = initial.get("campaign_type") or NewsletterCampaign.TYPE_GENERAL
        qs = NewsletterTemplate.objects.all()
        if campaign_type == NewsletterCampaign.TYPE_WEEKLY_NEWS:
            candidate = qs.filter(name__icontains="weekly").order_by("-updated_at", "-created_at").first()
            if not candidate:
                candidate = qs.order_by("-updated_at", "-created_at").first()
        else:
            candidate = qs.order_by("-updated_at", "-created_at").first()
        if candidate:
            initial["newsletter_template"] = candidate.pk
        return initial


class NewsletterCampaignViewSet(SnippetViewSet):
    model = NewsletterCampaign
    icon = "mail"
    menu_label = _("Newsletter campaigns")
    menu_order = 250
    add_to_admin_menu = False
    add_view_class = NewsletterCampaignCreateView
    form_class = NewsletterCampaignAdminForm
    base_form_class = NewsletterCampaignAdminForm
    list_display = ["title", "campaign_type", "list_id", "status", "scheduled_at", "sent_at", "updated_at"]
    list_filter = ["status"]
    search_fields = ["title", "list_id", "subject_template"]

    def get_form_class(self, for_update=False):
        return NewsletterCampaignAdminForm

    panels = [
        FieldPanel("title"),
        FieldPanel("campaign_type"),
        FieldPanel(
            "newsletter_template",
            help_text=_("Choose a template; default is picked from campaign type."),
        ),
        FieldPanel(
            "list_id",
            help_text=_("Leave blank to use member_center_list_id from Newsletter System Settings."),
        ),
        FieldPanel("subject_template"),
        FieldPanel(
            "html_template",
            widget=NewsletterCampaignEditorWidget(
                features=["h2", "h3", "bold", "italic", "link", "image", "ul", "ol"],
            ),
            help_text=_("Use image picker/upload from Wagtail. Prefer image URLs instead of Base64 in CMS."),
            classname="newsletter-general-only",
        ),
        FieldPanel("text_template", classname="newsletter-general-only"),
        FieldPanel(
            "weekly_articles",
            widget=forms.CheckboxSelectMultiple(),
            classname="newsletter-weekly-only",
        ),
        FieldPanel("item_template_html", classname="newsletter-weekly-only"),
        FieldPanel("scheduled_at"),
    ]


class ReadOnlySnippetPermissionPolicy(ModelPermissionPolicy):
    def user_has_permission(self, user, action):
        if action in {"add", "change", "delete"}:
            return False
        return super().user_has_permission(user, action)


class ContactFormSubmissionViewSet(SnippetViewSet):
    model = ContactFormSubmission
    icon = "form"
    menu_label = "聯絡表單留言"
    menu_order = 240
    add_to_admin_menu = False
    inspect_view_enabled = True
    copy_view_enabled = False
    permission_policy = ReadOnlySnippetPermissionPolicy(ContactFormSubmission)
    list_display = [
        "created_at",
        Column("processing_status", label="處理狀態", accessor=_contact_status_value, sort_key="processing_status"),
        Column("spam_category", label="垃圾訊息判定", accessor=_contact_spam_category_value, sort_key="spam_category"),
        Column("category", label="留言類型", accessor=_contact_category_value, sort_key="category"),
        "name",
        "email",
        "ip_address",
    ]
    list_filter = ["processing_status", "spam_category", "category", "created_at"]
    search_fields = ["name", "email", "contact", "message", "source_page", "ip_address"]
    inspect_view_fields = [
        "name",
        "email",
        "contact",
        "category",
        "message",
        "source_page",
        "ip_address",
        "user_agent",
        "processing_status",
        "spam_category",
        "spam_source",
        "spam_checked_at",
        "scan_attempt_count",
        "send_attempt_count",
        "next_attempt_at",
        "processing_started_at",
        "notification_sent_at",
        "user_copy_sent_at",
        "last_error",
        "created_at",
        "updated_at",
    ]


class NewsletterDispatchRecordViewSet(SnippetViewSet):
    model = NewsletterDispatchRecord
    icon = "tasks"
    menu_label = _("Newsletter dispatch records")
    menu_order = 251
    add_to_admin_menu = False
    inspect_view_enabled = True
    copy_view_enabled = False
    permission_policy = ReadOnlySnippetPermissionPolicy(NewsletterDispatchRecord)
    list_display = [
        "campaign",
        "email",
        "subscriber_id",
        "status",
        "retry_count",
        "next_retry_at",
        "response_status",
        "created_at",
    ]
    list_filter = ["status", "created_at"]
    search_fields = ["email", "subscriber_id", "campaign__title"]


class NewsletterTemplateViewSet(SnippetViewSet):
    model = NewsletterTemplate
    icon = "doc-full-inverse"
    menu_label = _("Newsletter templates")
    menu_order = 252
    add_to_admin_menu = False
    form_class = NewsletterTemplateAdminForm
    base_form_class = NewsletterTemplateAdminForm
    list_display = ["name", "subject", "updated_at", "created_at"]
    search_fields = ["name", "subject"]
    panels = [
        FieldPanel("name"),
        FieldPanel("subject"),
        FieldPanel(
            "template_html",
            widget=NewsletterHtmlEditorWidget(
                attrs={
                    "rows": 28,
                    "placeholder": "Use {{email_body}} as the content placeholder.",
                }
            ),
        ),
        FieldPanel(
            "template_text",
            widget=forms.Textarea(
                attrs={
                    "rows": 8,
                    "placeholder": "Use {{email_body}} as the content placeholder.",
                }
            ),
        ),
    ]


class NewsletterAdminGroup(SnippetViewSetGroup):
    menu_label = _("Newsletter campaigns")
    menu_icon = "mail"
    menu_order = 250
    items = (NewsletterCampaignViewSet, NewsletterDispatchRecordViewSet, NewsletterTemplateViewSet)


register_snippet(NewsletterAdminGroup)
register_snippet(ContactFormSubmissionViewSet)


class ContactFormSubmissionReportMenuItem(MenuItem):
    def is_shown(self, request):
        return request.user.has_perm("base.view_contactformsubmission")


@hooks.register("register_reports_menu_item")
def register_contact_form_submission_report_menu_item():
    return ContactFormSubmissionReportMenuItem(
        "聯絡表單留言",
        reverse("wagtailsnippets_base_contactformsubmission:list"),
        name="contact-form-submissions",
        icon_name="form",
        order=600,
    )


@hooks.register("register_snippet_listing_buttons")
def newsletter_campaign_listing_buttons(snippet, user, next_url=None):
    if not isinstance(snippet, NewsletterCampaign):
        return
    if not user.has_perm(SEND_NEWSLETTER_PERMISSION):
        return
    if snippet.status == NewsletterCampaign.STATUS_SENDING:
        return

    label = _("Send now")
    yield Button(
        label,
        reverse("newsletter_campaign_send_now", args=[snippet.pk]),
        icon_name="mail",
        priority=15,
    )
