"""
Script to facilitate generating ontology given a root JSON config,
and cleaning a folder out of generated ontology classes.
"""
import os
import sys
import logging
import argparse
from argparse import RawTextHelpFormatter
from forte.data.ontology.ontology_code_generator import OntologyCodeGenerator

logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO"))
log = logging.getLogger(__name__)


def normalize_path(path):
    if path is None:
        return None
    return os.path.abspath(os.path.expanduser(path))


def create(args_):
    """
    Function for the `create` mode. Generates the ontology.
    Args:
        args_: parsed args for the `create` mode
    """
    spec_path = normalize_path(args_.spec)
    dest_path = normalize_path(args_.dest_path)
    spec_paths = (
        [normalize_path(config) for config in args_.spec_paths]
        if args_.spec_paths is not None
        else None
    )
    merged_path = normalize_path(args_.merged_path)
    leient_prefix = args_.lenient_prefix

    generator = OntologyCodeGenerator(spec_paths, args_.gen_all)
    if args_.no_dry_run is None:
        log.info(
            "Ontology will be generated in a temporary directory as "
            "--no_dry_run is not specified by the user."
        )
        args_.no_dry_run = False

    if leient_prefix:
        log.info("Will not enforce prefix check.")

    is_dry_run = not args_.no_dry_run
    include_init = not args_.exclude_init
    generated_folder = generator.generate(
        spec_path,
        dest_path,
        is_dry_run,
        include_init,
        merged_path,
        leient_prefix,
    )
    log.info("Ontology generated in the directory %s.", generated_folder)


def clean(args_):
    """
    Function for the `clean` mode. Cleans the given directory of generated
    files.
    Args:
        args_: parsed args for the `clean` mode
    """
    dir_ = normalize_path(args_.dir)
    generator = OntologyCodeGenerator()
    is_empty, del_dir = generator.cleanup_generated_ontology(dir_, args_.force)
    if not is_empty:
        log.info("Directory %s not empty, cannot delete completely.", dir_)
    else:
        log.info("Directory %s deleted.", dir_)
    if not args_.force:
        log.info("Deleted files moved to %s.", del_dir)


class OntologyGenerationParser(argparse.ArgumentParser):
    def error(self, message):
        sys.stderr.write("Error: %s\n" % message)
        self.print_help()
        sys.exit(2)


def main():
    create_example = (
        "generate_ontology create --spec "
        "ontology_specs/example/pet_shop.json"
    )
    clean_example = "generate_ontology clean --dir generated-files"

    file_description = "\n".join(
        [
            "Utility to automatically generate or create Python classes given "
            "the ontology.",
            "\n*create*: Generate ontology given a JSON specification.",
            f"Example: {create_example} --no_dry_run\n",
            "*clean*: Clean a folder of generated Python classes.",
            f"Example: {clean_example}",
        ]
    )

    parser = OntologyGenerationParser(
        description=file_description, formatter_class=RawTextHelpFormatter
    )
    subs = parser.add_subparsers(
        title="required commands", help="Select one of:"
    )

    # Parser for creating the ontology.
    create_parser = subs.add_parser("create", help="to create new ontology")
    create_parser.add_argument(
        "-i",
        "--spec",
        type=str,
        required=True,
        help="The main input JSON specification.",
    )

    create_parser.add_argument(
        "-r",
        "--no_dry_run",
        required=False,
        default=None,
        action="store_true",
        help="Generates the package tree in a temporary "
        "directory if true, ignores the argument "
        "`--dest_path`",
    )

    create_parser.add_argument(
        "-o",
        "--dest_path",
        type=str,
        required=False,
        default=os.getcwd(),
        help="Destination directory provided by the user"
        ". Only used when --no_dry_run is "
        "specified. The"
        " default directory is the current working "
        "directory.",
    )

    create_parser.add_argument(
        "-s",
        "--spec_paths",
        type=str,
        nargs="*",
        required=False,
        default=None,
        help="Paths in which the root and imported "
        "spec files are to be searched.",
    )

    create_parser.add_argument(
        "-m",
        "--merged_path",
        type=str,
        required=False,
        default=None,
        help="The destination file path for the merged" "file path.",
    )

    create_parser.add_argument(
        "-e",
        "--exclude_init",
        required=False,
        default=None,
        action="store_true",
        help="Excludes generation of `__init__.py` files"
        " in the already existing directories, if"
        "`__init__.py` not already present.",
    )

    create_parser.add_argument(
        "-a",
        "--gen_all",
        required=False,
        default=False,
        action="store_true",
        help="If True, will generate all the ontology,"
        "including the existing ones shipped with "
        "Forte.",
    )

    create_parser.add_argument(
        "-l",
        "--lenient_prefix",
        required=False,
        default=False,
        action="store_true",
        help="If True, will not enforce prefix check.",
    )

    create_parser.add_argument(
        "-n",
        "--namespace_depth",
        type=int,
        required=False,
        default=0,
        help="set an integer argument namespace_depth"
        "to allow customized number of levels of namespace packaging."
        "The generation of __init__.py for all the"
        "directory levels above namespace_depth will be disabled."
        "Default value is set to 0 to disable namespace packaging"
        "When namespace_depth<=0, namespace packaging will be disabled"
        "and __init__.py will be included in all directory levels",
    )

    create_parser.set_defaults(func=create)

    # Parsing for cleaning.
    clean_parser = subs.add_parser("clean", help="to clean up ontologies")

    clean_parser.add_argument(
        "-d",
        "--dir",
        type=str,
        required=True,
        help="Generated files to be cleaned from the " "directory path.",
    )

    clean_parser.add_argument(
        "-f",
        "--force",
        default=False,
        action="store_true",
        help="If true, skips the interactive deleting of "
        "folders. Use with caution.",
    )

    clean_parser.set_defaults(func=clean)

    options = parser.parse_args()
    options_func = getattr(options, "func", None)
    if options_func is not None:
        options.func(options)
    else:
        sys.stderr.write("Error: %s\n" % "wrong usage of the script.")
        OntologyGenerationParser().print_help()
        sys.exit(2)


if __name__ == "__main__":
    main()
