#!/usr/bin/env python
"""
This script recursively converts hcl2 files to json

Usage:
    hcl2tojson [-s] PATH [OUT_PATH]

Options:
    -s          Skip un-parsable files
    PATH        The path to convert
    OUT_PATH    The path to write files to
"""
import argparse
import json
import os
import sys

from lark import UnexpectedCharacters, UnexpectedToken

from . import load
from .parser import hcl2
from .version import __version__


def main():
    """The `console_scripts` entry point"""

    parser = argparse.ArgumentParser(description='This script recursively converts hcl2 files to json')
    parser.add_argument('-s', dest='skip', action='store_true', help='Skip un-parsable files')
    parser.add_argument('PATH', help='The file or directory to convert')
    parser.add_argument(
        'OUT_PATH',
        nargs='?',
        help='The path where to write files to. Optional when parsing a single file. '
             'Output is printed to stdout if OUT_PATH is blank'
    )
    parser.add_argument('--version', action='version', version=__version__)

    args = parser.parse_args()

    skippable_exceptions = (
        UnexpectedToken,
        UnexpectedCharacters,
        UnicodeDecodeError
    )

    if os.path.isfile(args.PATH):
        with open(args.PATH, 'r', encoding="utf-8") as in_file:
            # pylint: disable=R1732
            out_file = sys.stdout if args.OUT_PATH is None else open(args.OUT_PATH, 'w', encoding="utf-8")
            print(args.PATH, file=sys.stderr, flush=True)
            json.dump(hcl2.parse(in_file.read()), out_file)
            if args.OUT_PATH is None:
                out_file.write('\n')
                out_file.close()
    elif os.path.isdir(args.PATH):
        processed_files = set()
        if args.OUT_PATH is None:
            raise RuntimeError("Positional OUT_PATH parameter shouldn't be empty")
        if not os.path.exists(args.OUT_PATH):
            os.mkdir(args.OUT_PATH)
        for current_dir, _, files in os.walk(args.PATH):
            dir_prefix = os.path.commonpath([args.PATH, current_dir])
            relative_current_dir = os.path.relpath(current_dir, dir_prefix)
            current_out_path = os.path.normpath(os.path.join(args.OUT_PATH, relative_current_dir))
            if not os.path.exists(current_out_path):
                os.mkdir(current_out_path)
            for file_name in files:
                in_file_path = os.path.join(current_dir, file_name)
                out_file_path = os.path.join(current_out_path, file_name)
                out_file_path = os.path.splitext(out_file_path)[0] + '.json'

                # skip any files that we already processed or generated to avoid loops and file lock errors
                if in_file_path in processed_files or out_file_path in processed_files:
                    continue

                processed_files.add(in_file_path)
                processed_files.add(out_file_path)

                with open(in_file_path, 'r', encoding="utf-8") as in_file:
                    print(in_file_path, file=sys.stderr, flush=True)
                    try:
                        parsed_data = load(in_file)
                    except skippable_exceptions:
                        if args.skip:
                            continue
                        raise
                    with open(out_file_path, 'w', encoding="utf-8") as out_file:
                        json.dump(parsed_data, out_file)
    else:
        raise RuntimeError("Invalid Path", args.PATH)


if __name__ == "__main__":
    main()
