import uuid

from django.conf import settings
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from wagtail.admin.panels import FieldPanel, HelpPanel, MultiFieldPanel
from wagtail.contrib.settings.models import BaseSiteSetting, register_setting

from .constants import (
    DEFAULT_BUSINESS_ASSISTANT_MODE_LABEL,
    DEFAULT_ENABLED_BUSINESS_SKILLS,
    DEFAULT_ENABLED_ADMIN_SKILLS,
    DEFAULT_ENABLED_PUBLIC_SKILLS,
    DEFAULT_MAX_SKILL_CONTEXT_ITEMS,
    DISPLAY_MODE_BOTH,
    DISPLAY_MODE_DISABLED,
    DISPLAY_MODE_PAGE,
    DISPLAY_MODE_WIDGET,
    MODE_ADMIN,
    MODE_CUSTOMER,
    ROLE_ASSISTANT,
    ROLE_SYSTEM,
    ROLE_USER,
    SESSION_CLOSED,
    SESSION_ESCALATED,
    SESSION_OPEN,
    WIDGET_POSITION_BOTTOM_LEFT,
    WIDGET_POSITION_BOTTOM_RIGHT,
)


@register_setting
class AiAssistantSiteSettings(BaseSiteSetting):
    DISPLAY_MODE_CHOICES = [
        (DISPLAY_MODE_PAGE, _("Page only")),
        (DISPLAY_MODE_WIDGET, _("Widget only")),
        (DISPLAY_MODE_BOTH, _("Page and widget")),
        (DISPLAY_MODE_DISABLED, _("Disabled")),
    ]
    WIDGET_POSITION_CHOICES = [
        (WIDGET_POSITION_BOTTOM_RIGHT, _("Bottom right")),
        (WIDGET_POSITION_BOTTOM_LEFT, _("Bottom left")),
    ]

    customer_enabled = models.BooleanField(
        default=True, verbose_name=_("Enable customer assistant")
    )
    customer_display_mode = models.CharField(
        max_length=16,
        choices=DISPLAY_MODE_CHOICES,
        default=DISPLAY_MODE_PAGE,
        verbose_name=_("Customer display mode"),
        help_text=_(
            "Choose whether public chat is shown as a page, widget, both, or disabled."
        ),
    )
    admin_enabled = models.BooleanField(
        default=True, verbose_name=_("Enable admin assistant")
    )
    openai_api_key = models.CharField(
        max_length=255, blank=True, verbose_name=_("OpenAI API key")
    )
    openai_model = models.CharField(
        max_length=120, default="gpt-4o-mini", verbose_name=_("OpenAI model")
    )
    business_description = models.TextField(
        blank=True,
        default="",
        verbose_name=_("Business description"),
        help_text=_(
            "Short public-facing description of the business, website, or webshop."
        ),
    )
    assistant_tone = models.CharField(
        max_length=120,
        blank=True,
        default="",
        verbose_name=_("Assistant tone"),
        help_text=_("Optional tone guidance such as helpful, concise, or friendly."),
    )
    customer_system_prompt = models.TextField(
        blank=True,
        default="You are a helpful support assistant for this webshop/website.",
        verbose_name=_("Customer system prompt"),
    )
    admin_system_prompt = models.TextField(
        blank=True,
        default="You are an admin support assistant for editors and webshop owners.",
        verbose_name=_("Admin system prompt"),
    )
    escalation_email = models.EmailField(blank=True, verbose_name=_("Escalation email"))
    contact_page_url = models.CharField(
        max_length=255,
        blank=True,
        default="",
        verbose_name=_("Contact page URL"),
        help_text=_("Public-safe contact page URL or relative path."),
    )
    quote_page_url = models.CharField(
        max_length=255,
        blank=True,
        default="",
        verbose_name=_("Quote page URL"),
        help_text=_("Public-safe quote or project request page URL or relative path."),
    )
    booking_page_url = models.CharField(
        max_length=255,
        blank=True,
        default="",
        verbose_name=_("Booking page URL"),
        help_text=_("Public-safe booking or consultation page URL or relative path."),
    )
    public_support_email = models.EmailField(
        blank=True,
        default="",
        verbose_name=_("Public support email"),
        help_text=_("Optional public support email that may be shown to customers."),
    )
    contact_instructions = models.TextField(
        blank=True,
        default="",
        verbose_name=_("Contact instructions"),
        help_text=_(
            "Optional public-safe guidance for contacting support or requesting a quote."
        ),
    )
    max_context_messages = models.PositiveIntegerField(
        default=12, verbose_name=_("Max context messages")
    )
    public_assistant_instructions = models.TextField(
        blank=True,
        default="",
        verbose_name=_("Public assistant instructions"),
        help_text=_(
            "Optional public-facing site instructions that can be safely included in AI context."
        ),
    )
    admin_assistant_instructions = models.TextField(
        blank=True,
        default="",
        verbose_name=_("Admin assistant instructions"),
        help_text=_(
            "Optional staff-facing instructions that can be safely included in admin AI context."
        ),
    )
    business_assistant_enabled = models.BooleanField(
        default=False,
        verbose_name=_("Enable Business Assistant Mode"),
        help_text=_(
            "Disabled by default. When enabled, explicitly configured business skills may become available to permitted staff users."
        ),
    )
    business_assistant_requires_staff = models.BooleanField(
        default=True,
        verbose_name=_("Require staff access for Business Assistant Mode"),
        help_text=_(
            "Recommended default. Only staff users may access business-mode capabilities."
        ),
    )
    business_assistant_mode_label = models.CharField(
        max_length=80,
        blank=True,
        default=DEFAULT_BUSINESS_ASSISTANT_MODE_LABEL,
        verbose_name=_("Business assistant mode label"),
        help_text=_(
            "Optional label shown when business-mode capabilities are exposed."
        ),
    )
    business_assistant_instructions = models.TextField(
        blank=True,
        default="",
        verbose_name=_("Business assistant instructions"),
        help_text=_("Optional internal-only instructions for Business Assistant Mode."),
    )
    enabled_public_skills = models.CharField(
        max_length=255,
        blank=True,
        default=",".join(DEFAULT_ENABLED_PUBLIC_SKILLS),
        verbose_name=_("Enabled public skills"),
        help_text=_("Comma-separated built-in skill keys enabled for public chat."),
    )
    enabled_admin_skills = models.CharField(
        max_length=255,
        blank=True,
        default=",".join(DEFAULT_ENABLED_ADMIN_SKILLS),
        verbose_name=_("Enabled admin skills"),
        help_text=_("Comma-separated built-in skill keys enabled for admin chat."),
    )
    enabled_business_skills = models.CharField(
        max_length=255,
        blank=True,
        default=",".join(DEFAULT_ENABLED_BUSINESS_SKILLS),
        verbose_name=_("Enabled business skills"),
        help_text=_(
            "Comma-separated business skill keys enabled only when Business Assistant Mode is active."
        ),
    )
    max_skill_context_items = models.PositiveIntegerField(
        default=DEFAULT_MAX_SKILL_CONTEXT_ITEMS,
        verbose_name=_("Max skill context items"),
        help_text=_("Maximum structured context items a skill may contribute."),
    )
    widget_launcher_label = models.CharField(
        max_length=40,
        blank=True,
        default="",
        verbose_name=_("Widget launcher label"),
        help_text=_("Optional short label shown next to the floating launcher."),
    )
    widget_title = models.CharField(
        max_length=80,
        blank=True,
        default="",
        verbose_name=_("Widget title"),
        help_text=_("Title shown in the floating chat header."),
    )
    widget_welcome_text = models.TextField(
        blank=True,
        default="",
        verbose_name=_("Widget welcome text"),
        help_text=_("Optional helper text shown before the first message."),
    )
    widget_position = models.CharField(
        max_length=20,
        choices=WIDGET_POSITION_CHOICES,
        default=WIDGET_POSITION_BOTTOM_RIGHT,
        verbose_name=_("Widget position"),
    )
    hide_widget_on_checkout = models.BooleanField(
        default=True,
        verbose_name=_("Hide widget on basket, checkout, and payment pages"),
    )

    panels = [
        MultiFieldPanel(
            [
                FieldPanel("customer_enabled"),
                FieldPanel("customer_display_mode"),
                FieldPanel("admin_enabled"),
                FieldPanel("openai_api_key"),
                FieldPanel("openai_model"),
                FieldPanel("max_context_messages"),
                FieldPanel("max_skill_context_items"),
                FieldPanel("escalation_email"),
                FieldPanel("contact_page_url"),
                FieldPanel("quote_page_url"),
                FieldPanel("booking_page_url"),
                FieldPanel("public_support_email"),
                FieldPanel("contact_instructions"),
            ],
            heading=_("Runtime settings"),
        ),
        MultiFieldPanel(
            [
                HelpPanel(
                    content=_(
                        "Public skills are used only for customer/public chat. Admin skills are used for the standard staff assistant. Business skills are configured separately and are not used unless Business Assistant Mode is explicitly activated from the admin assistant flow."
                    )
                ),
                FieldPanel("business_description"),
                FieldPanel("assistant_tone"),
                FieldPanel("public_assistant_instructions"),
                FieldPanel("admin_assistant_instructions"),
                FieldPanel("enabled_public_skills"),
                FieldPanel("enabled_admin_skills"),
            ],
            heading=_("Platform skill settings"),
        ),
        MultiFieldPanel(
            [
                HelpPanel(
                    content=_(
                        "Business Assistant Mode is more powerful than the standard assistant. Keep it disabled unless you explicitly need staff-only business capabilities. Business skills are never exposed in public chat and must be explicitly requested from the admin assistant flow."
                    )
                ),
                FieldPanel("business_assistant_enabled"),
                FieldPanel("business_assistant_requires_staff"),
                FieldPanel("business_assistant_mode_label"),
                FieldPanel("business_assistant_instructions"),
                FieldPanel("enabled_business_skills"),
            ],
            heading=_("Business Assistant Mode"),
        ),
        MultiFieldPanel(
            [
                FieldPanel("widget_launcher_label"),
                FieldPanel("widget_title"),
                FieldPanel("widget_welcome_text"),
                FieldPanel("widget_position"),
                FieldPanel("hide_widget_on_checkout"),
            ],
            heading=_("Widget settings"),
        ),
        MultiFieldPanel(
            [
                FieldPanel("customer_system_prompt"),
                FieldPanel("admin_system_prompt"),
            ],
            heading=_("Prompt settings"),
        ),
    ]

    class Meta:
        verbose_name = _("AI Assistant Settings")

    def public_chat_enabled(self) -> bool:
        return (
            self.customer_enabled
            and self.customer_display_mode != DISPLAY_MODE_DISABLED
        )

    def customer_page_enabled(self) -> bool:
        return self.public_chat_enabled() and self.customer_display_mode in {
            DISPLAY_MODE_PAGE,
            DISPLAY_MODE_BOTH,
        }

    def customer_widget_enabled(self) -> bool:
        return self.public_chat_enabled() and self.customer_display_mode in {
            DISPLAY_MODE_WIDGET,
            DISPLAY_MODE_BOTH,
        }

    def effective_widget_launcher_label(self) -> str:
        return (self.widget_launcher_label or "").strip() or _("Chat")

    def effective_widget_title(self) -> str:
        return (self.widget_title or "").strip() or _("AI Assistant")

    def effective_widget_welcome_text(self) -> str:
        return (self.widget_welcome_text or "").strip() or _(
            "Ask a question about this website or webshop and get a quick answer."
        )

    def enabled_skill_keys(self, mode: str) -> list[str]:
        raw_value = (
            self.enabled_admin_skills
            if mode == MODE_ADMIN
            else self.enabled_public_skills
        )
        if raw_value is None:
            default_keys = (
                DEFAULT_ENABLED_ADMIN_SKILLS
                if mode == MODE_ADMIN
                else DEFAULT_ENABLED_PUBLIC_SKILLS
            )
            return list(default_keys)
        parsed = [
            key.strip() for key in (raw_value or "").split(",") if key and key.strip()
        ]
        return parsed

    def enabled_business_skill_keys(self) -> list[str]:
        raw_value = self.enabled_business_skills
        if raw_value is None:
            return list(DEFAULT_ENABLED_BUSINESS_SKILLS)
        return [key.strip() for key in (raw_value or "").split(",") if key.strip()]

    def safe_mode_instructions(self, mode: str) -> str:
        value = (
            self.admin_assistant_instructions
            if mode == MODE_ADMIN
            else self.public_assistant_instructions
        )
        return (value or "").strip()


class AiAssistantSession(models.Model):
    MODE_CHOICES = [
        (MODE_CUSTOMER, _("Customer")),
        (MODE_ADMIN, _("Admin")),
    ]
    STATUS_CHOICES = [
        (SESSION_OPEN, _("Open")),
        (SESSION_CLOSED, _("Closed")),
        (SESSION_ESCALATED, _("Escalated")),
    ]

    uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    site_id = models.PositiveIntegerField(db_index=True)
    mode = models.CharField(max_length=20, choices=MODE_CHOICES, db_index=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL
    )
    visitor_id = models.CharField(max_length=64, blank=True, db_index=True)
    language_code = models.CharField(max_length=12, blank=True)
    status = models.CharField(
        max_length=20, choices=STATUS_CHOICES, default=SESSION_OPEN, db_index=True
    )
    source_path = models.CharField(max_length=255, blank=True)
    created_at = models.DateTimeField(default=timezone.now, db_index=True)
    updated_at = models.DateTimeField(auto_now=True)
    metadata = models.JSONField(default=dict, blank=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.mode}:{self.uuid}"


class AiAssistantMessage(models.Model):
    ROLE_CHOICES = [
        (ROLE_USER, _("User")),
        (ROLE_ASSISTANT, _("Assistant")),
        (ROLE_SYSTEM, _("System")),
    ]

    session = models.ForeignKey(
        AiAssistantSession, related_name="messages", on_delete=models.CASCADE
    )
    role = models.CharField(max_length=16, choices=ROLE_CHOICES)
    content = models.TextField()
    tokens_used = models.PositiveIntegerField(null=True, blank=True)
    created_at = models.DateTimeField(default=timezone.now, db_index=True)
    raw = models.JSONField(default=dict, blank=True)

    class Meta:
        ordering = ["created_at"]

    def __str__(self):
        return f"{self.role}:{self.created_at:%Y-%m-%d %H:%M}"
