"""Android entry point for LedGrab.

Called from Kotlin via Chaquopy to start/stop the FastAPI server
inside an Android application.  Sets up Android-specific paths
(app-private storage) before importing the main application.
"""

import asyncio
import json
import os
import threading
from typing import Any

_server_thread: threading.Thread | None = None
_server: Any | None = None  # uvicorn.Server
_loop: asyncio.AbstractEventLoop | None = None


def start_server(data_dir: str, port: int = 8080, api_key: str | None = None) -> None:
    """Start the LedGrab uvicorn server.

    Called from Kotlin's ``PythonBridge.startServer()``.  This function
    blocks until ``stop_server()`` is called, so Kotlin should invoke it
    on a background thread.

    Args:
        data_dir: Android app-private files directory
                  (e.g. ``/data/data/com.ledgrab.android/files``).
        port: HTTP port for the web UI / API.
        api_key: Optional Bearer token to enable LAN auth. When set,
                 published as ``LEDGRAB_AUTH__API_KEYS={"android":<key>}``
                 so the server's auth gate accepts LAN requests carrying
                 ``Authorization: Bearer <key>``. When None, the server
                 falls back to its default (loopback-only).
    """
    # ── Configure paths before any LedGrab imports ──────────────
    os.makedirs(os.path.join(data_dir, "data"), exist_ok=True)
    os.makedirs(os.path.join(data_dir, "data", "assets"), exist_ok=True)
    os.makedirs(os.path.join(data_dir, "config"), exist_ok=True)

    # Change working directory to app-private storage so relative
    # paths (e.g. "config/default_config.yaml") don't hit system dirs
    os.chdir(data_dir)

    os.environ["LEDGRAB_STORAGE__DATABASE_FILE"] = os.path.join(data_dir, "data", "ledgrab.db")
    os.environ["LEDGRAB_ASSETS__ASSETS_DIR"] = os.path.join(data_dir, "data", "assets")
    os.environ["LEDGRAB_SERVER__HOST"] = "0.0.0.0"
    os.environ["LEDGRAB_SERVER__PORT"] = str(port)

    # Provision LAN auth when the Kotlin launcher supplied a key. The
    # config layer (pydantic-settings) parses ``LEDGRAB_AUTH__API_KEYS``
    # as JSON when the value starts with `{`. We use a dict so the
    # rest of the codebase sees a labelled key just like the YAML
    # config form (api_keys: {android: ...}).
    if api_key:
        os.environ["LEDGRAB_AUTH__API_KEYS"] = json.dumps({"android": api_key})

    # ── Now safe to import LedGrab ──────────────────────────────
    import uvicorn  # noqa: E402

    from ledgrab.utils import setup_logging, get_logger  # noqa: E402

    setup_logging()
    logger = get_logger(__name__)
    logger.info("LedGrab Android: starting server on port %d", port)
    logger.info("Data directory: %s", data_dir)
    if api_key:
        logger.info("LedGrab Android: API key auth enabled (label=android)")
    else:
        logger.warning("LedGrab Android: no API key — LAN requests will be rejected")

    from ledgrab.config import get_config  # noqa: E402

    config = get_config()
    # Defensive: confirm the env var actually landed in the parsed config.
    # If pydantic-settings ever changes how it deserialises dict[str, str]
    # from env, the LAN auth would silently break (server would 401 every
    # phone scan). Logging the mismatch makes the failure mode obvious in
    # adb logcat.
    if api_key and config.auth.api_keys.get("android") != api_key:
        logger.error(
            "LedGrab Android: API key did NOT land in config — LAN auth will "
            "reject all requests. Check pydantic-settings dict parsing for "
            "LEDGRAB_AUTH__API_KEYS."
        )

    uv_config = uvicorn.Config(
        "ledgrab.main:app",
        host=config.server.host,
        port=port,
        log_level=config.server.log_level.lower(),
        # No uvloop/httptools on Android — use pure-Python asyncio
        loop="asyncio",
    )

    global _server, _loop
    _server = uvicorn.Server(uv_config)
    _loop = asyncio.new_event_loop()
    asyncio.set_event_loop(_loop)

    logger.info("LedGrab Android: server starting")
    _loop.run_until_complete(_server.serve())
    logger.info("LedGrab Android: server stopped")

    # Clean up so the next start_server() call begins fresh.
    _server = None
    _loop = None


def stop_server() -> None:
    """Signal the uvicorn server to shut down gracefully.

    Called from Kotlin's ``PythonBridge.stopServer()``.  Sets
    ``should_exit`` on the uvicorn Server which causes ``server.serve()``
    to return, unblocking the Python thread.
    """
    if _server is not None:
        _server.should_exit = True
