#!python
"""`ontodoc` CLI tool."""
# pylint: disable=wrong-import-position,wrong-import-order
import os
import sys
import argparse
import subprocess  # nosec

# Support running from uninstalled package by adding parent dir to sys path
rootdir = os.path.abspath(
    os.path.realpath((os.path.dirname(os.path.dirname(__file__))))
)
if rootdir not in sys.path:
    sys.path.insert(1, rootdir)

from ontopy import World, onto_path  # pylint: disable=import-error
from ontopy.ontodoc import (  # pylint: disable=import-error
    OntoDoc,
    get_format,
    get_style,
    get_figformat,
    get_maxwidth,
    get_docpp,
)

import owlready2


def main(argv: list = None):
    """Main run function.

    Parameters:
        argv: List of arguments, similar to `sys.argv[1:]`.
            Mainly for testing purposes, since it allows one to invoke the tool
            manually / through Python.

    """
    parser = argparse.ArgumentParser(
        description="Tool for documenting ontologies.",
        epilog=(
            "The easiest way to generate nice-looking documentation using "
            "pandoc is to copy the emmodoc example to the current directory "
            "and adapt it. See "
            "https://github.com/emmo-repo/EMMOntoPy/tree/master/examples/"
            "emmodoc for more info."
        ),
    )
    parser.add_argument(
        "iri",
        metavar="IRI",
        help="File name or URI of the ontology to document.",
    )
    parser.add_argument("outfile", metavar="OUTFILE", help="Output file.")

    parser.add_argument(
        "--database",
        "-d",
        metavar="FILENAME",
        default=":memory:",
        help=(
            "Load ontology from Owlready2 sqlite3 database. The `iri` argument"
            " should in this case be the IRI of the ontology you want to "
            "document."
        ),
    )
    parser.add_argument(
        "--local",
        "-l",
        action="store_true",
        help=(
            "Load imported ontologies locally. Their paths are specified in "
            "Protègè catalog files or via the --path option. The IRI should "
            "be a file name."
        ),
    )
    parser.add_argument(
        "--imported",
        "-i",
        action="store_true",
        help="Whether to also include imported ontologies.",
    )
    parser.add_argument(
        "--no-catalog",
        "-n",
        action="store_false",
        dest="url_from_catalog",
        default=None,
        help="Whether to not read catalog file even if it exists.",
    )
    parser.add_argument(
        "--catalog-file",
        default="catalog-v001.xml",
        help=(
            "Name of Protègè catalog file in the same folder as the ontology. "
            "This option is used together with --local and defaults to "
            '"catalog-v001.xml".'
        ),
    )
    parser.add_argument(
        "--path",
        action="append",
        default=[],
        help=(
            "Paths where imported ontologies can be found. May be provided as "
            "a comma-separated string and/or with multiple --path options."
        ),
    )
    parser.add_argument(
        "--reasoner",
        nargs="?",
        const="HermiT",
        choices=["HermiT", "Pellet"],
        help=(
            'Run given reasoner on the ontology. Valid reasoners are "HermiT" '
            '(default) and "Pellet". Note: these reasoners doesn\'t work well '
            "with EMMO."
        ),
    )
    parser.add_argument(
        "--template",
        "-t",
        metavar="FILE",
        help=(
            "ontodoc input template. If not provided, a simple default "
            "template will be used. Don't confuse it with the pandoc "
            "templates."
        ),
    )
    parser.add_argument(
        "--format",
        "-f",
        metavar="FORMAT",
        help=(
            'Output format. May be "md", "simple-html" or any other format '
            "supported by pandoc. By default the format is inferred from "
            "--output."
        ),
    )
    parser.add_argument(
        "--figdir",
        "-D",
        metavar="DIR",
        default="genfigs",
        help=(
            "Default directory to store generated figures. If a relative path "
            "is given, it is relative to the template (see --template), or the"
            " current directory, if --template is not given. Default: "
            '"genfigs"'
        ),
    )
    parser.add_argument(
        "--figformat",
        "-F",
        help=(
            "Format for generated figures. The default is inferred from "
            '"--format."'
        ),
    )
    parser.add_argument(
        "--max-figwidth",
        "-w",
        help="Maximum figure width.  The default is inferred from --format.",
    )
    parser.add_argument(
        "--pandoc-option",
        "-p",
        metavar="STRING",
        action="append",
        dest="pandoc_options",
        help=(
            "Additional pandoc long options overriding those read from "
            '--pandoc-option-file. Use "--pandoc-option=XXX=Y" to add pandoc '
            "option --XXX=Y. It is also possible to remove pandoc option --XXX"
            ' with "--pandoc-option=no-XXX".  This option may be provided '
            "multiple times."
        ),
    )
    parser.add_argument(
        "--pandoc-option-file",
        "-P",
        metavar="FILE",
        action="append",
        dest="pandoc_option_files",
        help=(
            "YAML file with additional pandoc options. Note, that default "
            'pandoc options are read from the files "pandoc-options.yaml" and '
            '"pandoc-FORMAT-options.yaml" (where FORMAT is format specified '
            "with --format). This option allows to override the defaults and "
            "add additional pandoc options. This option may be provided "
            "multiple times."
        ),
    )
    parser.add_argument(
        "--keep-generated",
        "-k",
        metavar="FILE",
        dest="genfile",
        help=(
            "Keep a copy of generated markdown input file for pandoc (for "
            "debugging)."
        ),
    )
    args = parser.parse_args(args=argv)

    # Append to onto_path
    for paths in args.path:
        for path in paths.split(","):
            if path not in onto_path:
                onto_path.append(path)

    # Load ontology
    world = World(filename=args.database)
    if args.database != ":memory:" and args.iri not in world.ontologies:
        parser.error(
            "The IRI argument should be one of the ontologies in the database:"
            "\n  " + "\n  ".join(world.ontologies.keys())
        )
    onto = world.get_ontology(args.iri)
    try:
        onto.load(
            only_local=args.local,
            url_from_catalog=args.url_from_catalog,
            catalog_file=args.catalog_file,
        )
    except owlready2.OwlReadyOntologyParsingError as exc:
        parser.error(f"error parsing {args.iri!r}: {exc}")

    # Sync reasoner
    if args.reasoner:
        onto.sync_reasoner(reasoner=args.reasoner)

    # Instantiate ontodoc instance
    fmt = get_format(args.outfile, args.format)
    style = get_style(fmt)
    figformat = args.figformat if args.figformat else get_figformat(fmt)
    maxwidth = args.max_figwidth if args.max_figwidth else get_maxwidth(fmt)
    ontodoc = OntoDoc(onto, style=style)
    res = get_docpp(
        ontodoc,
        args.template,
        figdir=args.figdir,
        figformat=figformat,
        maxwidth=maxwidth,
        imported=args.imported,
    )
    res.process()

    try:
        res.write(
            args.outfile,
            fmt=args.format,
            pandoc_option_files=args.pandoc_option_files,
            pandoc_options=args.pandoc_options,
            genfile=args.genfile,
        )
    except subprocess.CalledProcessError as exc:
        sys.exit(exc.returncode)  # Exit without traceback on pandoc errors

    return res


if __name__ == "__main__":
    docpp = main()
