# Copyright 2025 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import asyncio
import shlex
import uuid
from contextlib import asynccontextmanager
from typing import AsyncGenerator, Literal

import build_dir
from ffx_cmd import FfxCmd
from fx_cmd import FxCmd

_DEFAULT_SERVER_STARTUP_TIMEOUT = 30
_CHECK_SERVER_POLLING_INTERVAL = 0.2


class PackageServingException(Exception):
    """This exception is raised on unsuccessful package serving attempts."""


class PackageServingCLIException(SystemExit, PackageServingException):
    """
    Like `PackageServingException`, but does not print a stack trace when uncaught.

    Used in the `ensure_running()` asynccontextmanager function, where concise error messages are
    more helpful than noisy stack traces for CLI developer tools.
    """


async def is_running() -> bool:
    """
    Checks whether a package server is currently running.

    Returns:
        bool: Whether a package server is currently running.
    """
    cmd = await FxCmd().start("is-package-server-running")
    result = await cmd.run_to_completion()
    return result.return_code == 0


async def wait_for_package_server(
    process: asyncio.subprocess.Process, timeout: float, interval: float
) -> bool:
    """
    Waits for a package server to come online by periodically polling.
    Exits early if the given package serving process terminates.

    Args:
        process (Process): The package serving process. If it terminates early, this function
            automatically returns False.
        timeout (float): The maximum amount of time (in seconds) to wait for the package server.
        interval (float): The delay (in seconds) between each package server availability check.

    Returns:
        bool: Whether the package serving process is available within `timeout` seconds.
    """

    async def poll_is_running(interval: float) -> Literal[True]:
        while not await is_running():
            await asyncio.sleep(interval)
        return True

    async def wait_for_process(
        process: asyncio.subprocess.Process,
    ) -> Literal[False]:
        await process.wait()
        return False

    async def wait_for_timeout(timeout: float) -> Literal[False]:
        await asyncio.sleep(timeout)
        return False

    # This task represents the True condition: When `fx is-package-server-running` is True.
    poll_task = asyncio.create_task(poll_is_running(interval))

    # This task represents a False condition: When `process` terminates unexpectedly.
    process_task = asyncio.create_task(wait_for_process(process))

    # This task represents a False condition: When `timeout` has been reached.
    timeout_task = asyncio.create_task(wait_for_timeout(timeout))

    # Race the three tasks, we use the value of whichever task completes first.
    all_tasks = [poll_task, process_task, timeout_task]
    finished_task, _ = await asyncio.wait(
        all_tasks,
        return_when=asyncio.FIRST_COMPLETED,
    )

    is_serving = finished_task.pop().result() if finished_task else False

    # Cleanup other tasks.
    for task in all_tasks:
        task.cancel()
        try:
            await task
        except asyncio.CancelledError:
            pass

    return is_serving


def is_package_repository_built() -> bool:
    """
    Checks whether the in-tree package repository is built.

    Returns:
        bool: Whether the in-tree package repository is built.
    """
    return (
        build_dir.get_build_directory()
        / "amber-files"
        / "repository"
        / "9.root.json"
    ).is_file()


async def get_arguments(name: str | None = None) -> tuple[str, ...]:
    """
    Gets the ffx command line arguments for starting a package server.

    Args:
        name (str | None): Optionally specify the main repository name for this server.

    Returns:
        tuple[str, ...]: A tuple of ffx arguments for package serving.
    """
    repo_name = name or f"tmp-{uuid.uuid4()}"
    out_dir = build_dir.get_build_directory()
    ffx_default_port = await FfxCmd().start(
        "config",
        "get",
        "repository.server.default_port",
    )
    stdout = (await ffx_default_port.run_to_completion()).stdout
    try:
        port = int(stdout.strip(' \t\n\r"'))
    except ValueError:
        port = 8083

    # LINT.IfChange
    return (
        "repository",
        "server",
        "start",
        "--foreground",
        "--address",
        f"[::]:{port}",
        "--repository",
        repo_name,
        "--repo-path",
        str(out_dir / "amber-files"),
        "--trusted-root",
        str(out_dir / "amber-files" / "repository" / "9.root.json"),
        "--alias",
        "fuchsia.com",
        "--alias",
        "chromium.org",
    )
    # LINT.ThenChange(//tools/devshell/serve)


async def start(
    name: str | None = None, timeout: float = _DEFAULT_SERVER_STARTUP_TIMEOUT
) -> asyncio.subprocess.Process:
    """
    Starts a package server.

    Args:
        name (str | None): Optionally specify the main repository name for this server.
        timeout (float): The maximum amount of time (in seconds) to wait for the package server.

    Returns:
        Process: An asyncio Process instance for the package server.
    """
    if not is_package_repository_built():
        raise PackageServingException("The package repository is not built!")

    repo_name = name or f"tmp-{uuid.uuid4()}"
    ffx = FfxCmd()
    args = await get_arguments(repo_name)
    process = await asyncio.create_subprocess_exec(
        *ffx.command_line(*args),
        stdout=asyncio.subprocess.DEVNULL,
        stderr=asyncio.subprocess.DEVNULL,
    )

    if await wait_for_package_server(
        process, timeout, _CHECK_SERVER_POLLING_INTERVAL
    ):
        return process

    errmsg: str
    if process.returncode is None:
        errmsg = f"The package server didn't start within {timeout}s."
        process.terminate()
        await process.wait()
        await stop(repo_name)
    else:
        errmsg = f"The package server exited with code {process.returncode}."
    raise PackageServingException(errmsg + f"\nCommand: {shlex.join(args)}")


async def stop(name: str | None = None) -> None:
    """
    Stops running package servers.

    Args:
        name (str | None): Optionally specify the repository name of the server to terminate.
            If omitted, all package servers will be stopped.
    """
    process = await FfxCmd().start(
        "repository",
        "server",
        "stop",
        *([name] if name else []),
    )
    await process.run_to_completion()


@asynccontextmanager
async def ensure_running() -> AsyncGenerator[None, None]:
    """
    Starts a package server for the duration of the context block, if one is not currently running.
    """
    if await is_running():
        yield
        return

    try:
        repo_name = f"tmp-{uuid.uuid4()}"
        print(
            "You do not seem to have a package server running. "
            + "A temporary one will be started for the duration of this execution."
        )
        server = await start(repo_name)
    except PackageServingException as e:
        raise PackageServingCLIException(
            f"Error: {e}\nError: Failed to start the temporary package server. "
            + "You may need to manually start one via `fx serve`."
        )

    try:
        yield
    finally:
        server.terminate()
        await server.wait()

        # Sending SIGTERM doesn't seem to clean up child processes, so use `ffx` to stop the package
        # server we just started for good measure.
        await stop(repo_name)
