from __future__ import annotations

from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING:
    from .chatbot import Chatbot

# Accent name → hex colour
ACCENT_COLORS: dict[str, str] = {
    "indigo": "#6366f1",
    "violet": "#8b5cf6",
    "rose":   "#f43f5e",
    "emerald":"#10b981",
    "amber":  "#f59e0b",
    "blue":   "#3b82f6",
    "cyan":   "#06b6d4",
    "slate":  "#64748b",
}

# Accent name → Gradio built-in hue name
_GRADIO_HUES: dict[str, str] = {
    "indigo":  "indigo",
    "violet":  "purple",
    "rose":    "pink",
    "emerald": "green",
    "amber":   "yellow",
    "blue":    "blue",
    "cyan":    "cyan",
    "slate":   "slate",
}

# Only the bits that Gradio's theme engine can't handle cleanly
_EXTRA_CSS = """
/* ─── layout ─── */
.gradio-container {{
    max-width: 860px !important;
    margin: 0 auto !important;
    padding: 24px 12px !important;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif !important;
}}

/* ─── header ─── */
.ariel-header {{
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    border-radius: 12px 12px 0 0;
    background: {surface};
    border: 1px solid {border};
    border-bottom: none;
}}
.ariel-avatar {{
    width: 38px; height: 38px;
    border-radius: 10px;
    background: linear-gradient(135deg, {accent}, {accent}99);
    display: flex; align-items: center; justify-content: center;
    font-size: 19px; flex-shrink: 0;
}}
.ariel-title {{ font-size: 16px; font-weight: 700; color: {text}; }}
.ariel-sub   {{ font-size: 11px; color: {text_muted}; margin-top: 1px; }}
.ariel-pill  {{
    margin-left: auto;
    font-size: 11px; font-weight: 500;
    color: #22c55e;
    background: #22c55e18;
    border: 1px solid #22c55e44;
    border-radius: 20px;
    padding: 2px 10px;
    display: flex; align-items: center; gap: 5px;
}}
.ariel-dot {{
    width: 6px; height: 6px; border-radius: 50%; background: #22c55e;
    animation: blink 2s ease-in-out infinite;
}}
@keyframes blink {{ 0%,100% {{ opacity:1 }} 50% {{ opacity:.35 }} }}

/* ─── chat wrapper ─── */
.ariel-body {{
    border: 1px solid {border};
    border-top: none;
    border-radius: 0 0 12px 12px;
    overflow: hidden;
    background: {bg};
}}

/* ─── footer ─── */
.ariel-footer {{
    text-align: center; font-size: 11px; color: {text_muted};
    padding: 8px; border-top: 1px solid {border};
    background: {surface};
}}
.ariel-footer a {{ color: {accent}; text-decoration: none; }}

/* ─── hide Gradio chrome ─── */
footer {{ display: none !important; }}
"""


class ChatUI:
    """
    Polished Gradio Blocks UI for an ArielAI Chatbot.

    Examples::

        from arielai import Chatbot, ChatUI

        bot = Chatbot()
        ChatUI(bot, brand_name="Nova", accent="violet", dark_mode=True).launch()
    """

    def __init__(
        self,
        chatbot: "Chatbot",
        *,
        brand_name: Optional[str] = None,
        brand_emoji: str = "🤖",
        tagline: Optional[str] = None,
        accent: str = "indigo",
        dark_mode: bool = True,
        show_footer: bool = True,
        footer_text: str = "Built with ArielAI",
        footer_link: str = "https://pypi.org/project/arielai/",
        extra_css: str = "",
    ) -> None:
        self._bot = chatbot
        self.brand_name  = brand_name or chatbot.title
        self.brand_emoji = brand_emoji
        self.tagline     = tagline or f"{chatbot.model}  ·  {chatbot.backend_name}"
        self.accent      = ACCENT_COLORS.get(accent, accent)
        self._hue        = _GRADIO_HUES.get(accent, "indigo")
        self.dark_mode   = dark_mode
        self.show_footer = show_footer
        self.footer_text = footer_text
        self.footer_link = footer_link
        self.extra_css   = extra_css
        self._demo       = None

    # ── theme ────────────────────────────────────────────────────────────────

    def _make_theme(self):
        try:
            import gradio as gr
            theme = gr.themes.Soft(primary_hue=self._hue, neutral_hue="slate")
            if self.dark_mode:
                theme = theme.set(
                    body_background_fill="#0d0d14",
                    body_background_fill_dark="#0d0d14",
                    background_fill_primary="#13131f",
                    background_fill_primary_dark="#13131f",
                    background_fill_secondary="#1a1a28",
                    background_fill_secondary_dark="#1a1a28",
                    border_color_primary="#ffffff10",
                    border_color_primary_dark="#ffffff10",
                    block_background_fill="#13131f",
                    block_background_fill_dark="#13131f",
                    input_background_fill="#0d0d14",
                    input_background_fill_dark="#0d0d14",
                    body_text_color="#e2e8f0",
                    body_text_color_dark="#e2e8f0",
                    body_text_color_subdued="#64748b",
                    body_text_color_subdued_dark="#64748b",
                    chatbot_text_size="md",
                )
            return theme
        except Exception:
            try:
                import gradio as gr
                return gr.themes.Soft()
            except Exception:
                return None

    def _make_css(self) -> str:
        if self.dark_mode:
            palette = dict(
                bg="#0d0d14", surface="#13131f", border="#ffffff10",
                text="#e2e8f0", text_muted="#64748b",
            )
        else:
            palette = dict(
                bg="#f8fafc", surface="#ffffff", border="#e2e8f0",
                text="#0f172a", text_muted="#64748b",
            )
        css = _EXTRA_CSS.format(accent=self.accent, **palette)
        if self.extra_css:
            css += f"\n{self.extra_css}"
        return css

    # ── build ────────────────────────────────────────────────────────────────

    def build(self):
        try:
            import gradio as gr
        except ImportError as exc:
            raise ImportError("pip install arielai") from exc

        self._css   = self._make_css()
        self._theme = self._make_theme()

        with gr.Blocks(title=self.brand_name) as demo:

            gr.HTML(
                f'<div class="ariel-header">'
                f'  <div class="ariel-avatar">{self.brand_emoji}</div>'
                f'  <div>'
                f'    <div class="ariel-title">{self.brand_name}</div>'
                f'    <div class="ariel-sub">{self.tagline}</div>'
                f'  </div>'
                f'  <div class="ariel-pill">'
                f'    <div class="ariel-dot"></div>Online'
                f'  </div>'
                f'</div>'
            )

            with gr.Column(elem_classes=["ariel-body"]):
                gr.ChatInterface(
                    fn=self._bot.chat,
                    chatbot=gr.Chatbot(
                        elem_id="ariel-chatbot",
                        height=450,
                        render=False,
                        show_label=False,
                    ),
                    textbox=gr.Textbox(
                        placeholder=self._bot.placeholder,
                        container=False,
                        scale=7,
                        render=False,
                        show_label=False,
                    ),
                    examples=self._bot.examples,
                    fill_height=False,
                )
                if self.show_footer:
                    gr.HTML(
                        f'<div class="ariel-footer">'
                        f'<a href="{self.footer_link}" target="_blank">{self.footer_text}</a>'
                        f'</div>'
                    )

        self._demo = demo
        return demo

    # ── launch ───────────────────────────────────────────────────────────────

    def launch(
        self,
        share: bool = False,
        server_name: str = "0.0.0.0",
        server_port: Optional[int] = None,
        inbrowser: bool = True,
        **kwargs,
    ) -> None:
        demo = self.build()
        launch_kwargs: dict = dict(
            share=share,
            server_name=server_name,
            inbrowser=inbrowser,
            **kwargs,
        )
        if server_port is not None:
            launch_kwargs["server_port"] = server_port

        # Pass css/theme to launch() — required in Gradio 6+
        try:
            demo.launch(css=self._css, theme=self._theme, **launch_kwargs)
        except TypeError:
            # Older Gradio: pass theme to Blocks, not launch
            demo.launch(**launch_kwargs)

    def close(self) -> None:
        if self._demo:
            self._demo.close()

    def __enter__(self): return self
    def __exit__(self, *a): self.close()

    @staticmethod
    def list_accents() -> dict[str, str]:
        return dict(ACCENT_COLORS)
