"""Directive to generate a summary of listed objects."""
from __future__ import annotations

from docutils import nodes
from docutils.parsers.rst import directives
from sphinx.util.docutils import SphinxDirective

from autodoc2.sphinx.utils import (
    get_all_analyser,
    get_database,
    load_config,
    nested_parse_generated,
    warn_sphinx,
)
from autodoc2.utils import ItemData, WarningSubtypes


class AutodocSummary(SphinxDirective):
    """Directive to generate a summary of listed objects."""

    has_content = True
    required_arguments = 0
    optional_arguments = 0
    final_argument_whitespace = False
    option_spec = {
        "renderer": directives.unchanged_required,
    }

    def run(self) -> list[nodes.Node]:
        source, line = self.get_source_info()
        # warnings take the docname and line number
        warning_loc = (self.env.docname, line)

        all_resolver = get_all_analyser(self.env)

        # load the configuration
        overrides = {}
        if "renderer" in self.options:
            overrides = {"render_plugin": self.options["renderer"]}
        config = load_config(self.env.app, overrides=overrides, location=warning_loc)

        db = get_database(self.env)

        objects: list[ItemData] = []
        content_line: str
        aliases: dict[str, str] = {}
        for content_idx, content_line in enumerate(self.content):
            parts = content_line.strip().split(maxsplit=1)
            if len(parts) == 0:
                continue
            full_name = parts[0]
            alias: str | None = None
            if len(parts) > 1:
                alias = parts[1]
            if (item := db.get_item(full_name)) is None and (
                resolved_name := all_resolver.get_name(full_name)
            ):
                item = db.get_item(resolved_name)
            if item is not None:
                for ancestor in db.get_ancestors(full_name, include_self=True):
                    if ancestor and "file_path" in ancestor:
                        if file_path := ancestor["file_path"]:
                            self.env.note_dependency(file_path)
                        break
                if alias:
                    aliases[full_name] = alias
                objects.append(item)
            else:
                warn_sphinx(
                    f"Could not find {full_name}",
                    WarningSubtypes.NAME_NOT_FOUND,
                    location=(
                        self.env.docname,
                        line + self.content_offset + 1 + content_idx,
                    ),
                )

        if not objects:
            return []

        # setup warnings
        def _warn_render(msg: str, type_: WarningSubtypes) -> None:
            warn_sphinx(msg, type_, location=warning_loc)

        # TODO it would be ideal to create this as nodes, rather than nested parsing,
        # but for now this is the simplest option
        content = list(
            config.render_plugin(
                db,
                config,
                all_resolver=all_resolver,
                warn=_warn_render,
                standalone=True,
            ).generate_summary(objects, alias=aliases)
        )
        base = nested_parse_generated(self.state, content, source, line)

        return base.children or []
