from nicegui import ui
import db
import auth as auth_module
import layout


LANGUAGES = {
    "en": "English",
    "nl": "Dutch",
    "de": "German",
    "es": "Spanish",
    "fr": "French",
    "pt": "Portuguese",
}


@ui.page("/admin/mapper")
async def mapper_page():
    await auth_module.sync_session()
    if not auth_module.is_authenticated():
        ui.navigate.to("/login")
        return
    if not auth_module.is_superadmin():
        ui.navigate.to("/dashboard")
        return

    with layout.page("Mappers"):
        with ui.tabs().classes("w-full") as tabs:
            tab_lang = ui.tab("Language")
            tab_sem = ui.tab("Semantics")

        with ui.tab_panels(tabs, value=tab_lang).classes("w-full"):
            with ui.tab_panel(tab_lang):
                await _language_panel()
            with ui.tab_panel(tab_sem):
                await _semantics_panel()


# ── Language mapper ──────────────────────────────────────────────────────────


async def _language_panel():
    ui.label("Maps short metric keys to human-readable labels per language.").classes(
        "text-sm text-gray-500 -mt-2"
    )

    columns = [
        {
            "name": "key",
            "label": "Key",
            "field": "key",
            "align": "left",
            "sortable": True,
        },
        {
            "name": "lang",
            "label": "Language",
            "field": "_lang_label",
            "align": "left",
            "sortable": True,
        },
        {
            "name": "value",
            "label": "Label",
            "field": "value",
            "align": "left",
            "sortable": True,
        },
        {"name": "actions", "label": "", "field": "actions", "align": "right"},
    ]

    async def load():
        rows = await db.fetch(
            "SELECT key, value, lang FROM mapper_language ORDER BY key, lang"
        )
        return [
            {
                "_id": f"{r['key']}|{r['lang']}",
                "key": r["key"],
                "value": r["value"],
                "lang": r["lang"],
                "_lang_label": LANGUAGES.get(r["lang"], r["lang"]),
            }
            for r in rows
        ]

    row_data = await load()
    table = (
        ui.table(columns=columns, rows=row_data, row_key="_id")
        .classes("w-full")
        .props("flat")
    )

    # delete slot
    with table.add_slot("body-cell-actions"):
        with table.cell():
            ui.button(icon="delete").props("flat round dense color=negative").on(
                "click",
                js_handler="() => emit(props.row)",
                handler=lambda e: _lang_delete(e.args["key"], e.args["lang"], table),
            )

    async def refresh():
        table.rows = await load()
        table.update()

    # ── add dialog ───────────────────────────────────────────────────────────
    with ui.row().classes("w-full justify-end mt-2"):
        ui.button("Add entry", icon="add", on_click=lambda: add_dlg.open()).props(
            "color=primary"
        )

    with ui.dialog() as add_dlg, ui.card().classes("w-80 p-6 gap-4"):
        ui.label("Add language mapping").classes("text-lg font-semibold")
        key_in = ui.input("Key", placeholder="e.g. temp").classes("w-full")
        lang_in = ui.select(LANGUAGES, label="Language", value="en").classes("w-full")
        val_in = ui.input("Label", placeholder="e.g. temperature").classes("w-full")
        err = ui.label("").classes("text-red-500 text-sm")

        async def save_lang():
            err.text = ""
            if not all([key_in.value.strip(), val_in.value.strip()]):
                err.text = "Key and label are required."
                return
            try:
                await db.execute(
                    """
                    INSERT INTO mapper_language (key, value, lang) VALUES ($1, $2, $3)
                    ON CONFLICT DO NOTHING
                    """,
                    key_in.value.strip(),
                    val_in.value.strip(),
                    lang_in.value,
                )
                add_dlg.close()
                key_in.value = val_in.value = ""
                await refresh()
            except Exception as e:
                err.text = f"Error: {e}"

        with ui.row().classes("w-full justify-end gap-2 mt-2"):
            ui.button("Cancel", on_click=add_dlg.close).props("flat")
            ui.button("Save", on_click=save_lang).props("color=primary")


def _lang_delete(key: str, lang: str, table: ui.table):
    with ui.dialog() as dlg, ui.card().classes("p-6 gap-4"):
        ui.label(f'Delete "{key}" ({lang})?').classes("text-lg font-semibold")

        async def confirm():
            await db.execute(
                "DELETE FROM mapper_language WHERE key = $1 AND lang = $2",
                key,
                lang,
            )
            table.rows = [
                r for r in table.rows if not (r["key"] == key and r["lang"] == lang)
            ]
            table.update()
            dlg.close()

        with ui.row().classes("w-full justify-end gap-2"):
            ui.button("Cancel", on_click=dlg.close).props("flat")
            ui.button("Delete", on_click=confirm).props("color=negative")

    dlg.open()


# ── Semantics mapper ─────────────────────────────────────────────────────────


async def _semantics_panel():
    ui.label("Maps raw sensor/device keys to canonical metric names.").classes(
        "text-sm text-gray-500 -mt-2"
    )

    columns = [
        {
            "name": "key",
            "label": "Raw key",
            "field": "key",
            "align": "left",
            "sortable": True,
        },
        {
            "name": "value",
            "label": "Canonical name",
            "field": "value",
            "align": "left",
            "sortable": True,
        },
        {"name": "actions", "label": "", "field": "actions", "align": "right"},
    ]

    async def load():
        rows = await db.fetch("SELECT key, value FROM mapper_semantics ORDER BY key")
        return [{"key": r["key"], "value": r["value"]} for r in rows]

    row_data = await load()
    table = (
        ui.table(columns=columns, rows=row_data, row_key="key")
        .classes("w-full")
        .props("flat")
    )

    with table.add_slot("body-cell-actions"):
        with table.cell():
            ui.button(icon="delete").props("flat round dense color=negative").on(
                "click",
                js_handler="() => emit(props.row)",
                handler=lambda e: _sem_delete(e.args["key"], table),
            )

    async def refresh():
        table.rows = await load()
        table.update()

    # ── add dialog ───────────────────────────────────────────────────────────
    with ui.row().classes("w-full justify-end mt-2"):
        ui.button("Add entry", icon="add", on_click=lambda: add_dlg.open()).props(
            "color=primary"
        )

    with ui.dialog() as add_dlg, ui.card().classes("w-80 p-6 gap-4"):
        ui.label("Add semantic mapping").classes("text-lg font-semibold")
        key_in = ui.input(
            "Raw key", placeholder="e.g. R2_O2 MFC PV.R2_O2 MFC PV_pv"
        ).classes("w-full")
        val_in = ui.input("Canonical name", placeholder="e.g. O2").classes("w-full")
        err = ui.label("").classes("text-red-500 text-sm")

        async def save_sem():
            err.text = ""
            if not all([key_in.value.strip(), val_in.value.strip()]):
                err.text = "Both fields are required."
                return
            try:
                await db.execute(
                    """
                    INSERT INTO mapper_semantics (key, value) VALUES ($1, $2)
                    ON CONFLICT DO NOTHING
                    """,
                    key_in.value.strip(),
                    val_in.value.strip(),
                )
                add_dlg.close()
                key_in.value = val_in.value = ""
                await refresh()
            except Exception as e:
                err.text = f"Error: {e}"

        with ui.row().classes("w-full justify-end gap-2 mt-2"):
            ui.button("Cancel", on_click=add_dlg.close).props("flat")
            ui.button("Save", on_click=save_sem).props("color=primary")


def _sem_delete(key: str, table: ui.table):
    with ui.dialog() as dlg, ui.card().classes("p-6 gap-4"):
        ui.label(f'Delete mapping for "{key}"?').classes("text-lg font-semibold")

        async def confirm():
            await db.execute("DELETE FROM mapper_semantics WHERE key = $1", key)
            table.rows = [r for r in table.rows if r["key"] != key]
            table.update()
            dlg.close()

        with ui.row().classes("w-full justify-end gap-2"):
            ui.button("Cancel", on_click=dlg.close).props("flat")
            ui.button("Delete", on_click=confirm).props("color=negative")

    dlg.open()
