"""Login and settings page route handlers."""

from pathlib import Path

from itsdangerous import URLSafeTimedSerializer
from jinja2 import Environment, FileSystemLoader
from mcp.server.fastmcp import FastMCP
from starlette.requests import Request
from starlette.responses import HTMLResponse, RedirectResponse, Response

from bybit_mcp_server.auth.db import load_bybit_credentials, save_bybit_credentials
from bybit_mcp_server.auth.provider import complete_authorization, verify_admin_credentials
from bybit_mcp_server.config import get_secret_key

TEMPLATES_DIR = Path(__file__).parent / "templates"
SESSION_COOKIE = "bybit_mcp_session"
SESSION_MAX_AGE = 86400  # 24 hours

_jinja_env = Environment(loader=FileSystemLoader(str(TEMPLATES_DIR)), autoescape=True)


def _get_serializer() -> URLSafeTimedSerializer:
    return URLSafeTimedSerializer(get_secret_key())


def _create_session_cookie(username: str) -> str:
    return _get_serializer().dumps({"user": username})


def _verify_session_cookie(cookie: str) -> dict | None:
    try:
        return _get_serializer().loads(cookie, max_age=SESSION_MAX_AGE)
    except Exception:
        return None


def _render(template_name: str, **kwargs: object) -> HTMLResponse:
    template = _jinja_env.get_template(template_name)
    return HTMLResponse(template.render(**kwargs))


def register_settings_routes(mcp: FastMCP, db_path: str) -> None:
    """Register login and settings routes on the FastMCP server."""

    @mcp.custom_route("/login", methods=["GET", "POST"])
    async def login_page(request: Request) -> Response:
        request_id = request.query_params.get("request_id", "")

        if request.method == "GET":
            return _render("login.html", request_id=request_id)

        # POST: validate credentials
        form = await request.form()
        username = str(form.get("username", ""))
        password = str(form.get("password", ""))
        request_id = str(form.get("request_id", ""))

        if not verify_admin_credentials(username, password):
            return _render("login.html", request_id=request_id, error="Invalid credentials")

        # OAuth flow: complete authorization and redirect to Claude
        if request_id:
            redirect_url = complete_authorization(db_path, request_id)
            if redirect_url:
                return RedirectResponse(url=redirect_url, status_code=302)
            return _render("login.html", error="Authorization request expired. Please try again.")

        # Direct login: set session cookie and redirect to settings
        response = RedirectResponse(url="/settings", status_code=302)
        response.set_cookie(SESSION_COOKIE, _create_session_cookie(username), httponly=True, max_age=SESSION_MAX_AGE)
        return response

    @mcp.custom_route("/settings", methods=["GET", "POST"])
    async def settings_page(request: Request) -> Response:
        cookie = request.cookies.get(SESSION_COOKIE, "")
        session = _verify_session_cookie(cookie) if cookie else None
        if session is None:
            return RedirectResponse(url="/login", status_code=302)

        if request.method == "GET":
            creds = load_bybit_credentials(db_path)
            if creds:
                # Mask the API key for display
                key = creds["api_key"]
                masked_key = key[:4] + "****" + key[-4:] if len(key) > 8 else "****"
                return _render(
                    "settings.html",
                    api_key=masked_key,
                    has_credentials=True,
                    testnet=creds["testnet"],
                    mode=creds["mode"],
                    recv_window=creds["recv_window"],
                )
            return _render("settings.html", has_credentials=False, testnet=True, mode="read")

        # POST: save credentials
        form = await request.form()
        api_key = str(form.get("api_key", "")).strip()
        api_secret = str(form.get("api_secret", "")).strip()
        testnet = "testnet" in form
        mode = str(form.get("mode", "read"))
        recv_window_raw = str(form.get("recv_window", "")).strip()
        recv_window = int(recv_window_raw) if recv_window_raw else None

        if not api_key:
            return _render(
                "settings.html", error="API Key is required", has_credentials=False, testnet=testnet, mode=mode
            )

        # If api_secret is empty and we have existing credentials, keep the old secret
        if not api_secret:
            existing = load_bybit_credentials(db_path)
            if existing:
                api_secret = existing["api_secret"]
            else:
                return _render(
                    "settings.html", error="API Secret is required", has_credentials=False, testnet=testnet, mode=mode
                )

        # Strip masking if user didn't change the key
        existing = load_bybit_credentials(db_path)
        if existing and "****" in api_key:
            api_key = existing["api_key"]

        save_bybit_credentials(db_path, api_key, api_secret, testnet, mode, recv_window)

        # Re-render with success
        key_display = api_key[:4] + "****" + api_key[-4:] if len(api_key) > 8 else "****"
        return _render(
            "settings.html",
            api_key=key_display,
            has_credentials=True,
            testnet=testnet,
            mode=mode,
            recv_window=recv_window,
            success="Settings saved successfully.",
        )
