import logging
import subprocess

import click
from aiohttp import web

from envied.core import binaries
from envied.core.api import cors_middleware, setup_routes, setup_swagger
from envied.core.config import config
from envied.core.constants import context_settings


@click.command(
    short_help="Serve your Local Widevine Devices and REST API for Remote Access.", context_settings=context_settings
)
@click.option("-h", "--host", type=str, default="0.0.0.0", help="Host to serve from.")
@click.option("-p", "--port", type=int, default=8786, help="Port to serve from.")
@click.option("--caddy", is_flag=True, default=False, help="Also serve with Caddy.")
@click.option("--api-only", is_flag=True, default=False, help="Serve only the REST API, not pywidevine CDM.")
@click.option("--no-key", is_flag=True, default=False, help="Disable API key authentication (allows all requests).")
@click.option(
    "--debug-api",
    is_flag=True,
    default=False,
    help="Include technical debug information (tracebacks, stderr) in API error responses.",
)
def serve(host: str, port: int, caddy: bool, api_only: bool, no_key: bool, debug_api: bool) -> None:
    """
    Serve your Local Widevine Devices and REST API for Remote Access.

    \b
    Host as 127.0.0.1 may block remote access even if port-forwarded.
    Instead, use 0.0.0.0 and ensure the TCP port you choose is forwarded.

    \b
    You may serve with Caddy at the same time with --caddy. You can use Caddy
    as a reverse-proxy to serve with HTTPS. The config used will be the Caddyfile
    next to the unshackle config.

    \b
    The REST API provides programmatic access to unshackle functionality.
    Configure authentication in your config under serve.users and serve.api_secret.
    """
    from pywidevine import serve as pywidevine_serve

    log = logging.getLogger("serve")

    # Validate API secret for REST API routes (unless --no-key is used)
    if not no_key:
        api_secret = config.serve.get("api_secret")
        if not api_secret:
            raise click.ClickException(
                "API secret key is not configured. Please add 'api_secret' to the 'serve' section in your config."
            )
    else:
        api_secret = None
        log.warning("Running with --no-key: Authentication is DISABLED for all API endpoints!")

    if debug_api:
        log.warning("Running with --debug-api: Error responses will include technical debug information!")

    if caddy:
        if not binaries.Caddy:
            raise click.ClickException('Caddy executable "caddy" not found but is required for --caddy.')
        caddy_p = subprocess.Popen(
            [binaries.Caddy, "run", "--config", str(config.directories.user_configs / "Caddyfile")]
        )
    else:
        caddy_p = None

    try:
        if not config.serve.get("devices"):
            config.serve["devices"] = []
        config.serve["devices"].extend(list(config.directories.wvds.glob("*.wvd")))

        if api_only:
            # API-only mode: serve just the REST API
            log.info("Starting REST API server (pywidevine CDM disabled)")
            if no_key:
                app = web.Application(middlewares=[cors_middleware])
                app["config"] = {"users": []}
            else:
                app = web.Application(middlewares=[cors_middleware, pywidevine_serve.authentication])
                app["config"] = {"users": [api_secret]}
            app["debug_api"] = debug_api
            setup_routes(app)
            setup_swagger(app)
            log.info(f"REST API endpoints available at http://{host}:{port}/api/")
            log.info(f"Swagger UI available at http://{host}:{port}/api/docs/")
            log.info("(Press CTRL+C to quit)")
            web.run_app(app, host=host, port=port, print=None)
        else:
            # Integrated mode: serve both pywidevine + REST API
            log.info("Starting integrated server (pywidevine CDM + REST API)")

            # Create integrated app with both pywidevine and API routes
            if no_key:
                app = web.Application(middlewares=[cors_middleware])
                app["config"] = dict(config.serve)
                app["config"]["users"] = []
            else:
                app = web.Application(middlewares=[cors_middleware, pywidevine_serve.authentication])
                # Setup config - add API secret to users for authentication
                serve_config = dict(config.serve)
                if not serve_config.get("users"):
                    serve_config["users"] = []
                if api_secret not in serve_config["users"]:
                    serve_config["users"].append(api_secret)
                app["config"] = serve_config

            app.on_startup.append(pywidevine_serve._startup)
            app.on_cleanup.append(pywidevine_serve._cleanup)
            app.add_routes(pywidevine_serve.routes)
            app["debug_api"] = debug_api
            setup_routes(app)
            setup_swagger(app)

            log.info(f"REST API endpoints available at http://{host}:{port}/api/")
            log.info(f"Swagger UI available at http://{host}:{port}/api/docs/")
            log.info("(Press CTRL+C to quit)")
            web.run_app(app, host=host, port=port, print=None)
    finally:
        if caddy_p:
            caddy_p.kill()
