import json
import os
import sys
from glob import glob

import click
import tqdm
from concurrent.futures import ProcessPoolExecutor, as_completed

from conda_verify import __version__
from conda_verify.verify import Verify
from conda_verify.utilities import DummyExecutor, render_metadata, iter_cfgs


def _submit_verify_recipe(path, executor, ignore):
    futures = []
    for cfg in iter_cfgs():
        meta = render_metadata(path, cfg)
        if meta.get("build", {}).get("skip", "").lower() != "true":
            futures.append(
                executor.submit(
                    Verify.verify_recipe,
                    rendered_meta=meta,
                    recipe_dir=path,
                    checks_to_ignore=ignore,
                    exit_on_error=False,
                )
            )
    return futures


def _submit_verify_package(path, ignore):
    package_issues = (path, None)
    try:
        package_issues = Verify.verify_package(
            path_to_package=path, checks_to_ignore=ignore, exit_on_error=False
        )
    except (KeyError, OSError) as e:
        package_issues = (path, [str(e)])
    return package_issues


@click.command()
@click.argument("paths", nargs=-1, type=str)
@click.option("--ignore", nargs=1, type=str)
@click.option("--exit", is_flag=True)
@click.option("--debug", is_flag=True)
@click.option("--out-file", nargs=1, type=click.Path())
@click.version_option(prog_name="conda-verify", version=__version__)
def cli(paths, ignore, exit, debug, out_file):
    """conda-verify is a tool for validating conda packages and recipes.

    To validate a package:\n
    $  conda-verify path/to/package.tar.bz2

    To validate a recipe:\n
    $  conda-verify path/to/recipe_directory/
    """
    if ignore:
        ignore = ignore.split(",")

    package_issues = {}
    futures = []
    paths_glob = []
    for path in paths:
        glob_paths = glob(os.path.expanduser(path))
        if not glob_paths:
            print("Error: path spec %s didn't match any files" % path)
            sys.exit(1)
        paths_glob.extend(glob_paths)
    with (DummyExecutor if debug else ProcessPoolExecutor)() as executor:
        for path in paths_glob:
            meta_file = os.path.join(path, "meta.yaml")
            if os.path.isfile(meta_file):
                futures.extend(_submit_verify_recipe(path, executor, ignore))
            elif path.endswith((".tar.bz2", ".tar", ".conda")):
                futures.append(executor.submit(_submit_verify_package, path, ignore))
        for f in tqdm.tqdm(as_completed(futures), total=len(futures), leave=False):
            path, issues = f.result()
            if issues:
                package_issues[path] = issues

    if out_file:
        with open(out_file, "w") as f:
            json.dump(package_issues, f)
            print("saved to %s" % out_file)
    else:
        for path, issues in package_issues.items():
            print("-" * len(path))
            print(path)
            print("-" * len(path))
            for check in sorted(issues):
                try:
                    print(check, file=sys.stderr)
                except UnicodeEncodeError:
                    print(
                        "Could not print message for error code {} due to unicode error".format(
                            check.code
                        ),
                        file=sys.stderr,
                    )

    if exit and package_issues:
        sys.exit(1)
