import os
from pathlib import Path
from typing import Dict

import lxml.etree

from ..globals import directories
from ..globals.nxdl import NXDL_NAMESPACE
from ..nxdl import iter_definitions


def nxdl_indices() -> Dict[str, dict]:
    """For each directory under the NXDL root, create the content of an
    index file which link all NeXus class definition doc files.
    """
    indentation = " " * 4
    namespaces = {"nx": NXDL_NAMESPACE}
    sections = dict()
    root = directories.get_nxdl_root()

    for nxdl_file in iter_definitions():
        source = os.path.relpath(nxdl_file.parent, root)
        section = sections.get(source)
        if section is None:
            preample = _DIRNAME_TO_PREAMBLE.get(source)
            if preample is None:
                continue
            classes = []
            rst_lines = []
            index_file = directories.nxclass_build_root(nxdl_file) / "index.rst"
            sections[source] = {
                "index_file": index_file,
                "rst_lines": rst_lines,
                "classes": classes,
            }
            rst_lines.append(".. do NOT edit this file\n")
            rst_lines.append(f"   automatically generated by {__name__}\n")
            rst_lines.append("\n")
            rst_lines.append(preample)
            rst_lines.append("\n")
        else:
            classes = sections[source]["classes"]
            rst_lines = sections[source]["rst_lines"]

        nxclass_name = nxdl_file.with_suffix("").stem
        classes.append(nxclass_name)
        summary = get_nxclass_description(nxdl_file, namespaces)
        if "NXcg" in nxclass_name or "NXapm" in nxclass_name or "NXms" in nxclass_name:
            continue
        rst_lines.append("\n")
        rst_lines.append(f":ref:`{nxclass_name}`\n")
        rst_lines.append(f"{indentation}{summary}\n")

    # Create a table of content for each index file
    for section in sections.values():
        classes = section.pop("classes")
        rst_lines = section["rst_lines"]
        rst_lines.append("\n")
        rst_lines.append(".. toctree::\n")
        rst_lines.append(f"{indentation}:hidden:\n")
        rst_lines.append("\n")
        if "index_file" in section.keys():
            file = section["index_file"]
            print("----------", file)
            file = os.path.abspath(file)
        else:
            file = ""
            print("---------++++++++-", section)
        if file.endswith("contributed_definitions/index.rst"):
            rst_lines.append(f"{indentation}em-structure\n")
            rst_lines.append(f"{indentation}ellipsometry-structure\n")
            rst_lines.append(f"{indentation}mpes-structure\n")
            rst_lines.append(f"{indentation}apm-structure\n")
            rst_lines.append(f"{indentation}transport-structure\n")
            rst_lines.append(f"{indentation}sts-structure\n")
            rst_lines.append(f"{indentation}cgms-structure\n")
            rst_lines.append(f"{indentation}icme-structure\n")
            rst_lines.append(f"{indentation}sample-prep-structure\n")

        for cname in sorted(classes):
            rst_lines.append(f"{indentation}{cname}\n")

    return sections


def get_nxclass_description(nxdl_file: Path, namespaces) -> str:
    """
    get the summary line from each NXDL definition doc

    That's the first physical line of the doc string.
    """
    tree = lxml.etree.parse(nxdl_file)
    root = tree.getroot()
    nodes = root.xpath("nx:doc", namespaces=namespaces)
    if len(nodes) != 1:
        raise RuntimeError(f"wrong number of <doc> nodes in NXDL: {nxdl_file}")
    return nodes[0].text.strip().splitlines()[0]


_DIRNAME_TO_PREAMBLE = {
    "base_classes": """
.. index::
     ! see: class definitions; base class
     ! base class

.. _base.class.definitions:

Base Class Definitions
######################

A description of each NeXus base class definition is given.
NeXus base class definitions define the set of terms that
*might* be used in an instance of that class.
Consider the base classes as a set of *components*
that are used to construct a data file.
    """,
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    "applications": """
.. index::
     ! see: class definitions; application definition
     ! application definition

.. _application.definitions:

Application Definitions
#########################

A description of each NeXus application definition is given.
NeXus application definitions define the *minimum*
set of terms that
*must* be used in an instance of that class.
Application definitions also may define terms that
are optional in the NeXus data file.  The definition, in this case,
reserves the exact term by declaring its spelling and description.
Consider an application definition as a *contract*
between a data provider (such as the beam line control system) and a
data consumer (such as a data analysis program for a scientific technique)
that describes the information is certain to be available in a data file.

Use NeXus links liberally in data files to reduce duplication of data.
In application definitions involving raw data,
write the raw data in the :ref:`NXinstrument` tree and then link to it
from the location(s) defined in the relevant application definition.
    """,
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    "contributed_definitions": """
.. index::
     ! see: class definitions; contributed definition
     ! contributed definition

.. _contributed.definitions:

Contributed Definitions
#########################

A description of each NeXus contributed definition is given.
NXDL files in the NeXus contributed definitions include propositions from
the community for NeXus base classes or application definitions, as well
as other NXDL files for long-term archival by NeXus.  Consider the contributed
definitions as either in *incubation* or a special
case not for general use.  The :ref:`NIAC` is charged to review any new contributed
definitions and provide feedback to the authors before ratification
and acceptance as either a base class or application definition.

Some contributions are grouped together:
  :ref:`Optical Spectroscopy <Ellipsometry-Structure>`

  :ref:`Multi-dimensional Photoemission Spectroscopy <Mpes-Structure>`

  :ref:`Atomprobe Microscopy <Apm-Structure>`

  :ref:`Electron Microscopy <Em-Structure>`

  :ref:`Transport Measurements <Transport-Structure>`

  :ref:`Geometry and Microstructures  <CgmsFeatures-Structure>`


and others are simply listed here:

    """,
}
