"""Sphinx configuration for the aiopnsense documentation site."""

from __future__ import annotations

from datetime import datetime
import inspect
import logging
from pathlib import Path
import sys
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from sphinx.application import Sphinx

ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "scripts"))
sys.path.insert(0, str(Path(__file__).resolve().parent / "_ext"))

_LOGGER = logging.getLogger(__name__)

project: str = "aiopnsense"
author: str = "Snuffy2"
copyright: str = f"{datetime.now():%Y}, {author}"

extensions: list[str] = [
    "sphinx.ext.autodoc",
    "sphinx.ext.autosummary",
    "sphinx.ext.napoleon",
    "sphinx.ext.doctest",
    "sphinx.ext.intersphinx",
    "sphinx.ext.viewcode",
    "myst_parser",
    "opnsense_client_api",
    "sphinx_argparse_cli",
]

templates_path: list[str] = ["_templates"]
exclude_patterns: list[str] = ["_build", "_generated"]

autosummary_generate = True
autodoc_typehints = "description"
autodoc_member_order = "bysource"
autoclass_content = "both"
napoleon_google_docstring = True
napoleon_numpy_docstring = False
napoleon_use_param = True
napoleon_use_rtype = True

html_theme: str = "sphinx_rtd_theme"
html_title: str = "aiopnsense documentation"

html_theme_options = {
    "collapse_navigation": True,  # Items collapse when not in use (default)
    "navigation_depth": 2,  # Max depth of the TOC tree
    "version_selector": True,  # Display a version selector below the title.
}

intersphinx_mapping: dict[str, tuple[str, None]] = {
    "python": ("https://docs.python.org/3", None),
}


def append_pep702_deprecation(
    app: Sphinx,
    what: str,
    name: str,
    obj: object,
    options: object,
    lines: list[str],
) -> None:
    """Prepend PEP 702 deprecation metadata during an autodoc docstring event.

    Args:
        app (Sphinx): Sphinx application dispatching the event; unused by this hook.
        what (str): Autodoc object type, such as ``"function"`` or ``"class"``.
        name (str): Fully qualified name of the documented object.
        obj (object): Documented object, inspected for PEP 702 metadata.
        options (object): Autodoc directive options for the documented object.
        lines (list[str]): Mutable docstring source lines, updated in place to
            prepend the generated deprecation admonition.
    """
    del app, what, name, options

    deprecated_obj = obj.fget if isinstance(obj, property) else obj
    if not (
        deprecated_obj is not None
        and (inspect.isroutine(deprecated_obj) or inspect.isclass(deprecated_obj))
    ):
        return

    if not (message := getattr(deprecated_obj, "__deprecated__", None)):
        return

    if not isinstance(message, str):
        _LOGGER.warning("Ignoring non-string PEP 702 deprecation message for %s", deprecated_obj)
        return

    # PEP 702 does not include a "deprecated since" version. If we add our own
    # version metadata later, this can become a Sphinx versioned deprecation
    # directive.
    deprecation_lines = [f"   {message_line}" for message_line in message.splitlines()]
    lines[:0] = ["", ".. admonition:: Deprecated", "", *deprecation_lines, ""]


def setup(app: Sphinx) -> dict[str, bool]:
    """Register this extension's Sphinx event hooks.

    Args:
        app (Sphinx): Sphinx application used to register the autodoc docstring
            hook.

    Returns:
        dict[str, bool]: Sphinx extension metadata.
    """
    app.connect("autodoc-process-docstring", append_pep702_deprecation)
    return {"parallel_read_safe": True, "parallel_write_safe": True}
