"""
Account service s-expression page components.

Renders account dashboard, newsletters, fragment pages, login, and device
auth pages.  Called from route handlers in place of ``render_template()``.
"""
from __future__ import annotations

import os
from typing import Any

from shared.sx.jinja_bridge import load_service_components
from shared.sx.helpers import (
    call_url, sx_call, SxExpr,
    root_header_sx, full_page_sx,
)

# Load account-specific .sx components + handlers at import time
load_service_components(os.path.dirname(os.path.dirname(__file__)),
                        service_name="account")


# ---------------------------------------------------------------------------
# Header helpers
# ---------------------------------------------------------------------------

def _auth_nav_sx(ctx: dict) -> str:
    """Auth section desktop nav items."""
    parts = [
        sx_call("nav-link",
            href=call_url(ctx, "account_url", "/newsletters/"),
            label="newsletters",
            select_colours=ctx.get("select_colours", ""),
        )
    ]
    account_nav = ctx.get("account_nav")
    if account_nav:
        parts.append(account_nav)
    return "(<> " + " ".join(parts) + ")"


def _auth_header_sx(ctx: dict, *, oob: bool = False) -> str:
    """Build the account section header row."""
    return sx_call(
        "menu-row-sx",
        id="auth-row", level=1, colour="sky",
        link_href=call_url(ctx, "account_url", "/"),
        link_label="account", icon="fa-solid fa-user",
        nav=SxExpr(_auth_nav_sx(ctx)),
        child_id="auth-header-child", oob=oob,
    )


def _auth_nav_mobile_sx(ctx: dict) -> str:
    """Mobile nav menu for auth section."""
    parts = [
        sx_call("nav-link",
            href=call_url(ctx, "account_url", "/newsletters/"),
            label="newsletters",
            select_colours=ctx.get("select_colours", ""),
        )
    ]
    account_nav = ctx.get("account_nav")
    if account_nav:
        parts.append(account_nav)
    return "(<> " + " ".join(parts) + ")"


# ---------------------------------------------------------------------------
# Account dashboard (GET /)
# ---------------------------------------------------------------------------

def _account_main_panel_sx(ctx: dict) -> str:
    """Account info panel with user details and logout."""
    from quart import g
    from shared.browser.app.csrf import generate_csrf_token

    user = getattr(g, "user", None)
    error = ctx.get("error", "")

    error_sx = sx_call("account-error-banner", error=error) if error else ""

    user_email_sx = ""
    user_name_sx = ""
    if user:
        user_email_sx = sx_call("account-user-email", email=user.email)
        if user.name:
            user_name_sx = sx_call("account-user-name", name=user.name)

    logout_sx = sx_call("account-logout-form", csrf_token=generate_csrf_token())

    labels_sx = ""
    if user and hasattr(user, "labels") and user.labels:
        label_items = " ".join(
            sx_call("account-label-item", name=label.name)
            for label in user.labels
        )
        labels_sx = sx_call("account-labels-section",
                                items=SxExpr("(<> " + label_items + ")"))

    return sx_call(
        "account-main-panel",
        error=SxExpr(error_sx) if error_sx else None,
        email=SxExpr(user_email_sx) if user_email_sx else None,
        name=SxExpr(user_name_sx) if user_name_sx else None,
        logout=SxExpr(logout_sx),
        labels=SxExpr(labels_sx) if labels_sx else None,
    )


# ---------------------------------------------------------------------------
# Newsletters (GET /newsletters/)
# ---------------------------------------------------------------------------

def _newsletter_toggle_sx(un: Any, account_url_fn: Any, csrf_token: str) -> str:
    """Render a single newsletter toggle switch."""
    nid = un.newsletter_id
    toggle_url = account_url_fn(f"/newsletter/{nid}/toggle/")
    if un.subscribed:
        bg = "bg-emerald-500"
        translate = "translate-x-6"
        checked = "true"
    else:
        bg = "bg-stone-300"
        translate = "translate-x-1"
        checked = "false"
    return sx_call(
        "account-newsletter-toggle",
        id=f"nl-{nid}", url=toggle_url,
        hdrs=f'{{"X-CSRFToken": "{csrf_token}"}}',
        target=f"#nl-{nid}",
        cls=f"relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-offset-2 {bg}",
        checked=checked,
        knob_cls=f"inline-block h-4 w-4 rounded-full bg-white shadow transform transition-transform {translate}",
    )


def _newsletter_toggle_off_sx(nid: int, toggle_url: str, csrf_token: str) -> str:
    """Render an unsubscribed newsletter toggle (no subscription record yet)."""
    return sx_call(
        "account-newsletter-toggle",
        id=f"nl-{nid}", url=toggle_url,
        hdrs=f'{{"X-CSRFToken": "{csrf_token}"}}',
        target=f"#nl-{nid}",
        cls="relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-offset-2 bg-stone-300",
        checked="false",
        knob_cls="inline-block h-4 w-4 rounded-full bg-white shadow transform transition-transform translate-x-1",
    )


def _newsletters_panel_sx(ctx: dict, newsletter_list: list) -> str:
    """Newsletters management panel."""
    from shared.browser.app.csrf import generate_csrf_token

    account_url_fn = ctx.get("account_url") or (lambda p: p)
    csrf = generate_csrf_token()

    if newsletter_list:
        items = []
        for item in newsletter_list:
            nl = item["newsletter"]
            un = item.get("un")

            desc_sx = sx_call(
                "account-newsletter-desc", description=nl.description
            ) if nl.description else ""

            if un:
                toggle = _newsletter_toggle_sx(un, account_url_fn, csrf)
            else:
                toggle_url = account_url_fn(f"/newsletter/{nl.id}/toggle/")
                toggle = _newsletter_toggle_off_sx(nl.id, toggle_url, csrf)

            items.append(sx_call(
                "account-newsletter-item",
                name=nl.name,
                desc=SxExpr(desc_sx) if desc_sx else None,
                toggle=SxExpr(toggle),
            ))
        list_sx = sx_call(
            "account-newsletter-list",
            items=SxExpr("(<> " + " ".join(items) + ")"),
        )
    else:
        list_sx = sx_call("account-newsletter-empty")

    return sx_call("account-newsletters-panel", list=SxExpr(list_sx))


# ---------------------------------------------------------------------------
# Auth pages (login, device, check_email)
# ---------------------------------------------------------------------------

def _login_page_content(ctx: dict) -> str:
    """Login form content."""
    from shared.browser.app.csrf import generate_csrf_token
    from quart import url_for

    error = ctx.get("error", "")
    email = ctx.get("email", "")
    action = url_for("auth.start_login")

    error_sx = sx_call("auth-error-banner", error=error) if error else ""

    return sx_call(
        "auth-login-form",
        error=SxExpr(error_sx) if error_sx else None,
        action=action,
        csrf_token=generate_csrf_token(), email=email,
    )


def _device_page_content(ctx: dict) -> str:
    """Device authorization form content."""
    from shared.browser.app.csrf import generate_csrf_token
    from quart import url_for

    error = ctx.get("error", "")
    code = ctx.get("code", "")
    action = url_for("auth.device_submit")

    error_sx = sx_call("account-device-error", error=error) if error else ""

    return sx_call(
        "account-device-form",
        error=SxExpr(error_sx) if error_sx else None,
        action=action,
        csrf_token=generate_csrf_token(), code=code,
    )


def _device_approved_content() -> str:
    """Device approved success content."""
    return sx_call("account-device-approved")


# ---------------------------------------------------------------------------
# Public API: Account dashboard
# ---------------------------------------------------------------------------





def _fragment_content(frag: object) -> str:
    """Convert a fragment response to sx content string.

    SxExpr (from text/sx responses) is embedded as-is; plain strings
    (from text/html) are wrapped in ``~rich-text``.
    """
    from shared.sx.parser import SxExpr
    if isinstance(frag, SxExpr):
        return frag.source
    s = str(frag) if frag else ""
    if not s:
        return ""
    return f'(~rich-text :html "{_sx_escape(s)}")'


# ---------------------------------------------------------------------------
# Public API: Auth pages (login, device)
# ---------------------------------------------------------------------------

async def render_login_page(ctx: dict) -> str:
    """Full page: login form."""
    hdr = root_header_sx(ctx)
    return full_page_sx(ctx, header_rows=hdr,
                          content=_login_page_content(ctx),
                          meta_html='<title>Login \u2014 Rose Ash</title>')


async def render_device_page(ctx: dict) -> str:
    """Full page: device authorization form."""
    hdr = root_header_sx(ctx)
    return full_page_sx(ctx, header_rows=hdr,
                          content=_device_page_content(ctx),
                          meta_html='<title>Authorize Device \u2014 Rose Ash</title>')


async def render_device_approved_page(ctx: dict) -> str:
    """Full page: device approved."""
    hdr = root_header_sx(ctx)
    return full_page_sx(ctx, header_rows=hdr,
                          content=_device_approved_content(),
                          meta_html='<title>Device Authorized \u2014 Rose Ash</title>')


# ---------------------------------------------------------------------------
# Public API: Check email page (POST /start/ success)
# ---------------------------------------------------------------------------

def _check_email_content(email: str, email_error: str | None = None) -> str:
    """Check email confirmation content."""
    from markupsafe import escape

    error_sx = sx_call(
        "auth-check-email-error", error=str(escape(email_error))
    ) if email_error else ""

    return sx_call(
        "auth-check-email",
        email=str(escape(email)),
        error=SxExpr(error_sx) if error_sx else None,
    )


async def render_check_email_page(ctx: dict) -> str:
    """Full page: check email after magic link sent."""
    email = ctx.get("email", "")
    email_error = ctx.get("email_error")
    hdr = root_header_sx(ctx)
    return full_page_sx(ctx, header_rows=hdr,
                          content=_check_email_content(email, email_error),
                          meta_html='<title>Check your email \u2014 Rose Ash</title>')


# ---------------------------------------------------------------------------
# Public API: Fragment renderers for POST handlers
# ---------------------------------------------------------------------------


def render_newsletter_toggle(un) -> str:
    """Render a newsletter toggle switch for POST response (uses account_url)."""
    from shared.browser.app.csrf import generate_csrf_token
    from quart import g
    account_url_fn = getattr(g, "_account_url", None)
    if account_url_fn is None:
        from shared.infrastructure.urls import account_url
        account_url_fn = account_url
    return _newsletter_toggle_sx(un, account_url_fn, generate_csrf_token())


# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------

def _sx_escape(s: str) -> str:
    """Escape a string for embedding in sx string literals."""
    return s.replace("\\", "\\\\").replace('"', '\\"')
