from __future__ import annotations

import asyncio
from pathlib import Path
from typing import Dict

from nicegui import app, ui

from nemo_library_etl.adapter.migman.config_store import MigManConfigStore
from nemo_library_etl.adapter.migman.migmanutils import MigManUtils
from nemo_library_etl.adapter.migman.symbols import MIGMAN_PROJECT_POSTFIX_SEPARATOR

from .render_context import UIRenderContext
from .sections import (
    render_extract,
    render_global,
    render_load,
    render_overview,
    render_setup,
    render_transform,
)
from .ui_controller_migman import MigManUIController, MigManUIRuntime
from .ui_help_de import get_tooltip_de
from .ui_help_en import get_help_markdown_en, get_help_title_en, get_tooltip_en

SECTIONS = [
    ("Global", render_global),
    ("Setup", render_setup),
    ("Extract", render_extract),
    ("Transform", render_transform),
    ("Load", render_load),
    ("Overview", render_overview),
]


class MigManUI:
    def __init__(self) -> None:
        self.config_store = MigManConfigStore()

    def load_configurations(self) -> tuple[dict, dict, dict]:
        return self.config_store.load_merged()

    def save_configuration(self, config_data: Dict[str, Any]) -> bool:
        ok, msg = self.config_store.save_local(config_data)
        ui.notify(msg, type="positive" if ok else "negative")
        return ok

    def reset_configuration(self) -> bool:
        ok, msg = self.config_store.reset_local()
        ui.notify(msg, type="positive" if ok else "negative")
        return ok

    def run_ui(self, *, open_browser: bool = True) -> None:
        """Start the NiceGUI interface for MigMan configuration.

        Args:
            open_browser: whether to open the browser automatically
        """

        connected_clients = set()
        global_config, local_config, merged_config = self.load_configurations()

        dark_mode_enabled = merged_config.get("ui_dark_model", True)

        migmandatabase = MigManUtils.MigManDatabaseLoad()
        migmanprojects = sorted(
            [
                project_name
                for project_name in [
                    (
                        (f"{m.project} {MIGMAN_PROJECT_POSTFIX_SEPARATOR} {m.postfix}")
                        if m.postfix and m.project
                        else m.project
                    )
                    for m in migmandatabase
                ]
                if project_name is not None
            ]
        )
        migmanprojects = sorted(list(set(migmanprojects)))

        form_state = {"data": merged_config.copy()}
        if "ui_dark_model" not in form_state["data"]:
            form_state["data"]["ui_dark_model"] = dark_mode_enabled

        @app.on_connect
        def on_connect(client):
            connected_clients.add(client.id)

        @app.on_disconnect
        async def on_disconnect(client):
            connected_clients.discard(client.id)
            if not connected_clients:
                await asyncio.sleep(0.3)
                app.shutdown()

        @ui.page("/")
        def index() -> None:
            ui.page_title("DataMate UI")
            runtime = MigManUIRuntime(
                global_config=global_config,
                local_config=local_config,
                merged_config=merged_config,
                form_state=form_state,
                state={"dark": dark_mode_enabled},
                has_changes={"value": False},
                active={"value": "Global"},
            )

            ui_language = (runtime.form_state.get("data", {}) or {}).get("ui_language", "en")

            def get_tip(key: str, default: str = "") -> str:
                if str(ui_language).lower().startswith("de"):
                    return get_tooltip_de(key, default)
                return get_tooltip_en(key, default)

            controller = MigManUIController(self, runtime)
            state = runtime.state
            has_changes = runtime.has_changes
            nav_buttons = runtime.nav_buttons
            active = runtime.active
            transform_tab_state = {"value": "Join"}

            controller.set_dark_mode_from_config(state["dark"])

            def mark_changed() -> None:
                controller.mark_changed()

            def mark_saved() -> None:
                controller.mark_saved()

            def set_active(name: str) -> None:
                controller.set_active(name)

            def save_config() -> None:
                controller.save()

            def reset_config() -> None:
                controller.reset()

            def on_toggle(e) -> None:
                controller.toggle_dark_mode(e.value)

            convenience_hooks = {"refresh_quick_setup": lambda: None}
            ctx = UIRenderContext(
                ui_app=self,
                runtime=runtime,
                controller=controller,
                content_container=None,
                transform_tab_state=transform_tab_state,
                convenience_hooks=convenience_hooks,
                migmanprojects=migmanprojects,
                get_tip=get_tip,
                renderers=runtime.renderers,
                mark_changed=mark_changed,
                mark_saved=mark_saved,
                set_active=set_active,
                save_config=save_config,
                reset_config=reset_config,
            )

            with ui.element("div").classes("fixed top-2 right-4 z-50"):
                with ui.row().classes("items-center gap-3"):
                    @ui.refreshable
                    def render_help_dialog_content() -> None:
                        ui.markdown(
                            get_help_markdown_en(active["value"], transform_tab_state["value"])
                        ).classes("prose max-w-none")

                    with ui.dialog() as help_dialog, ui.card().classes("w-[min(900px,95vw)]"):
                        ui.label(
                            get_help_title_en(active["value"], transform_tab_state["value"])
                        ).classes("text-lg font-semibold")
                        render_help_dialog_content()
                        with ui.row().classes("justify-end mt-2"):
                            ui.button("Close", on_click=help_dialog.close).props("flat")

                    def confirm_reset() -> None:
                        async def on_confirm():
                            reset_config()
                            dialog.close()

                        async def on_cancel():
                            dialog.close()

                        with ui.dialog() as dialog, ui.card():
                            ui.label("Reset Configuration").classes("text-lg font-semibold")
                            ui.label(
                                "Do you really want to delete all individual configurations and reset to default values?"
                            ).classes("mb-4")

                            with ui.row().classes("gap-2 justify-end"):
                                ui.button("Cancel", on_click=on_cancel).props("flat")
                                ui.button("Reset", on_click=on_confirm).props("color=negative")

                        dialog.open()

                    ui.button("Reset", icon="restart_alt", on_click=confirm_reset).props(
                        "color=negative outline"
                    ).tooltip(get_tip("global.reset"))

                    save_button = ui.button("Save", icon="save", on_click=save_config).bind_enabled_from(
                        has_changes, "value"
                    )
                    save_button.tooltip(get_tip("global.save"))

                    dark_mode_label = ui.label("Dark mode")
                    dark_mode_label.tooltip(get_tip("global.dark_mode"))
                    dark_mode_switch = ui.switch(on_change=on_toggle).bind_value(state, "dark")
                    dark_mode_switch.tooltip(get_tip("global.dark_mode"))

                    def open_help_dialog() -> None:
                        render_help_dialog_content.refresh()
                        help_dialog.open()

                    ui.button("Help", icon="help_outline", on_click=open_help_dialog).tooltip(
                        get_tip("global.help")
                    )

                    convenience_hooks.get("refresh_quick_setup", lambda: None)()

            def make_renderer(fn):
                def renderer() -> None:
                    fn(ctx)

                return renderer

            runtime.renderers.update({name: make_renderer(fn) for name, fn in SECTIONS})

            def nav_to(name: str) -> None:
                set_active(name)
                runtime.renderers[name]()

            with ui.left_drawer(value=True, fixed=True).classes("w-64 p-4"):
                ui.label("DataMate Configuration").classes("text-lg font-semibold mb-4")

                def make_nav_button(name: str, cb):
                    button = ui.button(name, on_click=cb).props("flat").classes("w-full justify-start mb-2")
                    nav_buttons[name] = button
                    return button

                for name, _fn in SECTIONS:
                    make_nav_button(name, lambda n=name: nav_to(n))

            with ui.element("div"):
                with ui.column() as content:
                    ctx.content_container = content
                    nav_to("Global")

        favicon_path = Path(__file__).resolve().parent.parent / "static" / "favicon.png"
        ui.run(reload=False, show=open_browser, favicon=str(favicon_path))
