"""
title: UI Language Debugger
author: Fu-Jie
author_url: https://github.com/Fu-Jie/awesome-openwebui
funding_url: https://github.com/open-webui
version: 0.1.0
icon_url: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPgogIDxwYXRoIGQ9Im01IDggNiA2Ii8+CiAgPHBhdGggZD0ibTQgMTQgNi02IDItMiIvPgogIDxwYXRoIGQ9Ik0yIDVoMTIiLz4KICA8cGF0aCBkPSJNNyAyaDEiLz4KICA8cGF0aCBkPSJtMjIgMjItNS0xMC01IDEwIi8+CiAgPHBhdGggZD0iTTE0IDE4aDYiLz4KPC9zdmc+Cg==
description: Debug UI language detection in the browser console and on-page panel.
"""

import json
import logging
from typing import Optional, Dict, Any, Callable, Awaitable
from pydantic import BaseModel, Field

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)

HTML_WRAPPER_TEMPLATE = """
<!-- OPENWEBUI_PLUGIN_OUTPUT -->
<!DOCTYPE html>
<html lang="{user_language}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            margin: 0;
            padding: 10px;
            background-color: transparent;
        }
        #main-container {
            display: flex;
            flex-direction: column;
            gap: 16px;
            width: 100%;
            max-width: 100%;
        }
        /* STYLES_INSERTION_POINT */
    </style>
</head>
<body>
    <div id="main-container">
        <!-- CONTENT_INSERTION_POINT -->
    </div>
    <!-- SCRIPTS_INSERTION_POINT -->
</body>
</html>
"""

CONTENT_TEMPLATE = """
<div class="lang-debug-card" id="lang-debug-card-{unique_id}">
    <div class="lang-debug-header">
        🧭 UI Language Debugger
    </div>
    <div class="lang-debug-body">
        <div class="lang-debug-row"><span>python.ui_language</span><code id="lang-py-{unique_id}">{python_language}</code></div>
        <div class="lang-debug-row"><span>document.documentElement.lang</span><code id="lang-html-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>document.documentElement.getAttribute('lang')</span><code id="lang-attr-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>document.documentElement.dir</span><code id="lang-dir-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>document.body.lang</span><code id="lang-body-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>navigator.language</span><code id="lang-nav-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>navigator.languages</span><code id="lang-navs-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>localStorage.language</span><code id="lang-store-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>localStorage.locale</span><code id="lang-locale-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>localStorage.i18n</span><code id="lang-i18n-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>localStorage.settings</span><code id="lang-settings-{unique_id}">-</code></div>
        <div class="lang-debug-row"><span>document.documentElement.dataset</span><code id="lang-dataset-{unique_id}">-</code></div>
    </div>
</div>
"""

STYLE_TEMPLATE = """
.lang-debug-card {
    border: 1px solid #e2e8f0;
    border-radius: 12px;
    background: #ffffff;
    overflow: hidden;
    box-shadow: 0 2px 10px rgba(15, 23, 42, 0.06);
}
.lang-debug-header {
    padding: 12px 16px;
    background: linear-gradient(135deg, #6366f1, #8b5cf6);
    color: #fff;
    font-weight: 600;
}
.lang-debug-body {
    padding: 12px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.lang-debug-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 0.9em;
    color: #1f2937;
}
.lang-debug-row code {
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    padding: 2px 6px;
    border-radius: 6px;
    color: #0f172a;
}
"""

SCRIPT_TEMPLATE = """
<script>
(function() {{
    const uniqueId = "{unique_id}";
    const get = (id) => document.getElementById(id + '-' + uniqueId);

    const safe = (value) => {
        if (value === undefined || value === null || value === "") return "-";
        if (Array.isArray(value)) return value.join(", ");
        if (typeof value === "object") return JSON.stringify(value);
        return String(value);
    };

    const safeJson = (value) => {
        try {
            return value ? JSON.stringify(JSON.parse(value)) : "-";
        } catch (e) {
            return value ? String(value) : "-";
        }
    };

    const settingsRaw = localStorage.getItem('settings');
    const i18nRaw = localStorage.getItem('i18n');
    const localeRaw = localStorage.getItem('locale');

    const payload = {{
        htmlLang: document.documentElement.lang,
        htmlAttr: document.documentElement.getAttribute('lang'),
        htmlDir: document.documentElement.dir,
        bodyLang: document.body ? document.body.lang : "",
        navigatorLanguage: navigator.language,
        navigatorLanguages: navigator.languages,
        localStorageLanguage: localStorage.getItem('language'),
        localStorageLocale: localeRaw,
        localStorageI18n: i18nRaw,
        localStorageSettings: settingsRaw,
        htmlDataset: document.documentElement.dataset,
    }};

    get('lang-html').textContent = safe(payload.htmlLang);
    get('lang-attr').textContent = safe(payload.htmlAttr);
    get('lang-dir').textContent = safe(payload.htmlDir);
    get('lang-body').textContent = safe(payload.bodyLang);
    get('lang-nav').textContent = safe(payload.navigatorLanguage);
    get('lang-navs').textContent = safe(payload.navigatorLanguages);
    get('lang-store').textContent = safe(payload.localStorageLanguage);
    get('lang-locale').textContent = safe(payload.localStorageLocale);
    get('lang-i18n').textContent = safeJson(payload.localStorageI18n);
    get('lang-settings').textContent = safeJson(payload.localStorageSettings);
    get('lang-dataset').textContent = safe(payload.htmlDataset);

    console.group('🧭 UI Language Debugger');
    console.log(payload);
    console.groupEnd();
}})();
</script>
"""


class Action:
    class Valves(BaseModel):
        SHOW_STATUS: bool = Field(
            default=True,
            description="Whether to show operation status updates.",
        )
        SHOW_DEBUG_LOG: bool = Field(
            default=True,
            description="Whether to print debug logs in the browser console.",
        )

    def __init__(self):
        self.valves = self.Valves()

    def _get_user_context(self, __user__: Optional[Dict[str, Any]]) -> Dict[str, str]:
        if isinstance(__user__, (list, tuple)):
            user_data = __user__[0] if __user__ else {}
        elif isinstance(__user__, dict):
            user_data = __user__
        else:
            user_data = {}

        return {
            "user_id": user_data.get("id", "unknown_user"),
            "user_name": user_data.get("name", "User"),
            "user_language": user_data.get("language", ""),
        }

    def _get_chat_context(
        self, body: dict, __metadata__: Optional[dict] = None
    ) -> Dict[str, str]:
        chat_id = ""
        message_id = ""

        if isinstance(body, dict):
            chat_id = body.get("chat_id", "")
            message_id = body.get("id", "")

            if not chat_id or not message_id:
                body_metadata = body.get("metadata", {})
                if isinstance(body_metadata, dict):
                    if not chat_id:
                        chat_id = body_metadata.get("chat_id", "")
                    if not message_id:
                        message_id = body_metadata.get("message_id", "")

        if __metadata__ and isinstance(__metadata__, dict):
            if not chat_id:
                chat_id = __metadata__.get("chat_id", "")
            if not message_id:
                message_id = __metadata__.get("message_id", "")

        return {
            "chat_id": str(chat_id).strip(),
            "message_id": str(message_id).strip(),
        }

    async def _emit_status(
        self,
        emitter: Optional[Callable[[Any], Awaitable[None]]],
        description: str,
        done: bool = False,
    ):
        if self.valves.SHOW_STATUS and emitter:
            await emitter(
                {"type": "status", "data": {"description": description, "done": done}}
            )

    async def _emit_debug_log(
        self,
        emitter: Optional[Callable[[Any], Awaitable[None]]],
        title: str,
        data: dict,
    ):
        if not self.valves.SHOW_DEBUG_LOG or not emitter:
            return

        try:
            js_code = f"""
                (async function() {{
                    console.group("🛠️ {title}");
                    console.log({json.dumps(data, ensure_ascii=False)});
                    console.groupEnd();
                }})();
            """

            await emitter({"type": "execute", "data": {"code": js_code}})
        except Exception as e:
            logger.error("Error emitting debug log: %s", e, exc_info=True)

    def _merge_html(
        self,
        existing_html: str,
        new_content: str,
        new_styles: str = "",
        new_scripts: str = "",
        user_language: str = "en-US",
    ) -> str:
        if not existing_html:
            base_html = HTML_WRAPPER_TEMPLATE.replace("{user_language}", user_language)
        else:
            base_html = existing_html

        if "<!-- CONTENT_INSERTION_POINT -->" in base_html:
            base_html = base_html.replace(
                "<!-- CONTENT_INSERTION_POINT -->",
                f"{new_content}\n        <!-- CONTENT_INSERTION_POINT -->",
            )

        if new_styles and "/* STYLES_INSERTION_POINT */" in base_html:
            base_html = base_html.replace(
                "/* STYLES_INSERTION_POINT */",
                f"{new_styles}\n        /* STYLES_INSERTION_POINT */",
            )

        if new_scripts and "<!-- SCRIPTS_INSERTION_POINT -->" in base_html:
            base_html = base_html.replace(
                "<!-- SCRIPTS_INSERTION_POINT -->",
                f"{new_scripts}\n    <!-- SCRIPTS_INSERTION_POINT -->",
            )

        return base_html

    async def action(
        self,
        body: dict,
        __user__: Optional[Dict[str, Any]] = None,
        __event_emitter__: Optional[Any] = None,
        __event_call__: Optional[Callable[[Any], Awaitable[None]]] = None,
        __metadata__: Optional[dict] = None,
        __request__: Optional[Any] = None,
    ) -> Optional[dict]:
        await self._emit_status(__event_emitter__, "Detecting UI language...", False)

        user_ctx = self._get_user_context(__user__)
        await self._emit_debug_log(
            __event_emitter__,
            "Language Debugger: user context",
            user_ctx,
        )

        ui_language = ""
        if __event_call__:
            try:
                response = await __event_call__(
                    {
                        "type": "execute",
                        "data": {
                            "code": "return (localStorage.getItem('locale') || localStorage.getItem('language') || (navigator.languages && navigator.languages[0]) || navigator.language || document.documentElement.lang || '')",
                        },
                    }
                )
                await self._emit_debug_log(
                    __event_emitter__,
                    "Language Debugger: execute response",
                    {"response": response},
                )
                if isinstance(response, dict) and "value" in response:
                    ui_language = response.get("value", "") or ""
                elif isinstance(response, str):
                    ui_language = response
            except Exception as e:
                logger.error(
                    "Failed to read UI language from frontend: %s", e, exc_info=True
                )

        unique_id = f"lang_{int(__import__('time').time() * 1000)}"
        content_html = CONTENT_TEMPLATE.replace("{unique_id}", unique_id).replace(
            "{python_language}", ui_language or "-"
        )
        script_html = SCRIPT_TEMPLATE.replace("{unique_id}", unique_id)
        script_html = script_html.replace("{{", "{").replace("}}", "}")

        final_html = self._merge_html(
            "",
            content_html,
            STYLE_TEMPLATE,
            script_html,
            "en",
        )

        html_embed_tag = f"```html\n{final_html}\n```"
        body["messages"][-1]["content"] = (
            body["messages"][-1].get("content", "") + "\n\n" + html_embed_tag
        )

        await self._emit_status(__event_emitter__, "UI language captured.", True)
        return body
