#!/usr/bin/env python
"""
This script obtains the dependencies for the terraform config wrapper files and applies them.

Usage:
    graph_apply --path=PATH [--operation=OPERATION] [--parallel-jobs=NUM_JOBS] [--debug] [--print-only-changes]
    graph_apply --version

Arguments:
    path    The path of the config directory to check

Options:
    -h, --help                                   Show this message and exit.[default: False]
    -p, PATH --path=PATH                         Path to the directory to execute.
    -o, OPERATION --operation=OPERATION          Which terraform command to run in the directories defined in
                                                 the pipeline file.
                                                 [default: plan]
    -j, NUM_JOBS --parallel-jobs=NUM_JOBS        The number of Terraform operations to run in parallel.
                                                 [default: 4].
    -v,--debug                                   Turns on debug logging.
    --print-only-changes                         Only print output for directories that have changes.
    --version                                    Display the current version of Terraform Wrapper.
"""

import os
import networkx

from docopt import docopt

from terrawrap.exceptions import NoDependency
from terrawrap.utils.version import version_check
from terrawrap.version import __version__

from terrawrap.utils.config import walk_and_graph_directory, walk_without_graph_directory
from terrawrap.utils.graph import find_source_nodes, generate_dependencies, visualize, connect_symlinks
from terrawrap.models.graph import ApplyGraph
from terrawrap.utils.path import get_symlinks


SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
CURRENT_DIRECTORY = os.getcwd()


def main():
    version_check(current_version=__version__)
    arguments = docopt(__doc__, version="Terrawrap %s" % __version__)

    operation = arguments['--operation'].strip()
    debug = arguments['--debug']
    print_only_changes = arguments['--print-only-changes']
    try:
        num_parallel = int(arguments['--parallel-jobs'])
    except ValueError:
        raise RuntimeError(
            "Unable to parse number of parallel jobs, '%s' is not an integer." % arguments['--parallel-jobs']
        )

    config_dir = arguments['--path']
    if not os.path.isabs(config_dir):
        config_dir = os.path.abspath(os.path.join(CURRENT_DIRECTORY, config_dir))
    if not os.path.isdir:
        config_dir = os.path.dirname(config_dir)

    wrapper_config_dict = {}

    print("Visualizing Dependencies for %s:" % config_dir)
    try:
        graph, post_graph = walk_and_graph_directory(config_dir, wrapper_config_dict)
    except ValueError:
        print("Terrawrap has detected no dependency information in this graph, attempting to apply all directories")
        graph = networkx.DiGraph()
        try:
            post_graph = walk_without_graph_directory(config_dir)
        except NoDependency:
            post_graph = []
            print("Discovered dependency information, please either remove all dependency info or fix existing.")
            print("This error generally occurs due to malformed dependency information.")
            exit(1)

    symlinks_dict = get_symlinks(config_dir)

    connect_symlinks(graph, symlinks_dict)

    sources = find_source_nodes(graph)
    dependencies = generate_dependencies(sources, graph)
    visualize(dependencies)
    if post_graph:
        print("The following files have not been configured and will be run in parallel after the graph has run.")
        relative_post_graph = []
        for directory in post_graph:
            relative_path = directory.replace(os.getcwd(), "")
            relative_post_graph.append(relative_path)
        print(relative_post_graph)

    apply = ApplyGraph(operation, graph, post_graph, config_dir)
    apply.execute_graph(
        num_parallel=num_parallel,
        debug=debug,
        print_only_changes=print_only_changes
    )
    apply.execute_post_graph(
        num_parallel=num_parallel,
        debug=debug,
        print_only_changes=print_only_changes
    )
    if apply.not_applied:
        print("SKIPPED DIRECTORIES")
        print("The following directories have not been run since they are out of scope")
        print(apply.not_applied)
    if apply.failures:
        print("FAILED DIRECTORIES")
        print(
            "The following directories failed with command '%s':\n%s" % (operation, "\n".join(apply.failures))
            )
        print(
            "Terrawrap has detected failures while running terraform %s, "
            "please check above for specific directories." % operation
        )
        exit(1)


if __name__ == '__main__':
    main()
