"""Command-line DFD diagram generator. Converts a textual description
into a graphic file.

-----

See https://github.com/pbauermeister/dfd for information, syntax and
examples.

-----

This module parses the commandline args, prepares the I/Os and calls the stuff.
"""

import argparse
import os
import sys
import tempfile
from typing import TextIO

import pkg_resources

from . import dfd, dot, markdown, model
from .console import print_error, dprint, set_debug

try:
    VERSION = pkg_resources.require("data-flow-diagram")[0].version
except pkg_resources.DistributionNotFound:
    VERSION = "undefined"


def parse_args() -> argparse.Namespace:
    assert __doc__ is not None
    description, epilog = [each.strip() for each in __doc__.split("-----")[:2]]

    parser = argparse.ArgumentParser(description=description, epilog=epilog)

    parser.add_argument(
        "INPUT_FILE",
        action="store",
        default=None,
        nargs="?",
        help="UML sequence input file; " "if omitted, stdin is used",
    )

    parser.add_argument(
        "--output-file",
        "-o",
        required=False,
        help="output file name; pass '-' to use stdout; "
        "if omitted, use INPUT_FILE base name with '.svg' "
        "extension, or stdout",
    )

    parser.add_argument(
        "--markdown",
        "-m",
        action="store_true",
        help="consider snippets between opening marker: "
        "```data-flow-diagram OUTFILE, and closing marker: ``` "
        "allowing to generate all diagrams contained in an "
        "INPUT_FILE that is a markdown file",
    )

    parser.add_argument(
        "--format",
        "-f",
        required=False,
        default="svg",
        help="output format: gif, jpg, tiff, bmp, pnm, eps, "
        "pdf, svg (any supported by Graphviz); default is svg",
    )

    parser.add_argument(
        "--percent-zoom",
        "-p",
        required=False,
        default=100,
        type=int,
        help="magnification percentage; default is 100",
    )

    parser.add_argument(
        "--background-color",
        "-b",
        required=False,
        default="white",
        help="background color name (including 'none' for"
        " transparent) in web color notation; see"
        " https://developer.mozilla.org/en-US/docs/Web/CSS/color_value"
        " for a list of valid names; default is white",
    )

    parser.add_argument(
        "--no-graph-title",
        action="store_true",
        default=False,
        help="suppress graph title",
    )

    parser.add_argument(
        "--no-check-dependencies",
        action="store_true",
        default=False,
        help="suppress dependencies checking",
    )

    parser.add_argument(
        "--debug",
        action="store_true",
        default=False,
        help="emit debug messages",
    )

    parser.add_argument(
        "--version",
        "-V",
        action="store_true",
        help="print the version and exit",
    )

    return parser.parse_args()


def handle_markdown_source(
    options: model.Options, provenance: str, input_fp: TextIO
) -> None:
    text = input_fp.read()
    snippets = markdown.extract_snippets(text)
    markdown.check_snippets_unicity(provenance, snippets)
    snippets_params = markdown.make_snippets_params(provenance, snippets)
    for params in snippets_params:
        dfd.build(
            params.root,
            params.input_fp.read(),
            params.file_name,
            options,
            snippet_by_name=params.snippet_by_name,
        )
        dprint(f"{sys.argv[0]}: generated {params.file_name}")


def handle_dfd_source(
    options: model.Options, provenance: str, input_fp: TextIO, output_path: str
) -> None:
    root = model.SourceLine("", provenance, None, 0)
    if output_path == "-":
        # output to stdout
        with tempfile.TemporaryDirectory() as d:
            path = os.path.join(d, "file.svg")
            dfd.build(root, input_fp.read(), path, options)
            with open(path) as f:
                print(f.read())
    else:
        # output to file
        dfd.build(root, input_fp.read(), output_path, options)


def run(args: argparse.Namespace) -> None:
    # adjust input
    if args.INPUT_FILE is None:
        input_fp = sys.stdin
        provenance = "<stdin>"
    else:
        input_fp = open(args.INPUT_FILE)
        provenance = f"<file:{args.INPUT_FILE}>"

    options = model.Options(
        args.format,
        args.percent_zoom,
        args.background_color,
        args.no_graph_title,
        args.no_check_dependencies,
        args.debug,
    )

    set_debug(args.debug)

    # markdown source
    if args.markdown:
        handle_markdown_source(options, provenance, input_fp)
        return

    # adjust output
    if args.output_file is None:
        if args.INPUT_FILE is not None:
            basename = os.path.splitext(args.INPUT_FILE)[0]
            output_path = basename + "." + args.format
        else:
            output_path = "-"
    else:
        output_path = args.output_file

    # DFD source
    handle_dfd_source(options, provenance, input_fp, output_path)


def main() -> None:
    """Entry point for the application script"""

    dot.check_installed()

    args = parse_args()
    if args.version:
        print("data-flow-diagram", VERSION)
        sys.exit(0)

    try:
        run(args)
    except model.DfdException as e:
        text = f"ERROR: {e}"
        print_error(text)
        sys.exit(1)
