import argparse
import asyncio
import datetime

from updatable import utils as updatable_utils


def _str_to_bool(value):
    """
    Converts a string into a bool

    :param pacvaluekage_name: string
    """
    if isinstance(value, bool):
        return value
    if value.lower() in ("yes", "true", "t", "y", "1"):
        return True
    elif value.lower() in ("no", "false", "f", "n", "0"):
        return False
    else:
        raise argparse.ArgumentTypeError("Boolean value expected!")


async def _list_package_updates(package_name, version, show_pre_releases=False):
    """
    Function used to list all package updates in console

    :param package_name: string
    :param version: string
    :param show_pre_releases bool
    """
    updates = await updatable_utils.get_package_update_list(package_name, version)
    has_displayed_updates = updates["newer_releases"] or (show_pre_releases and updates["pre_releases"])
    current_release_license = updates["current_release_license"]

    if has_displayed_updates:
        print(f"{package_name} ({version}) - License: {current_release_license}")

    if updates["newer_releases"]:
        _list_updates("Major releases", updates["major_updates"], current_release_license)
        _list_updates("Minor releases", updates["minor_updates"], current_release_license)
        _list_updates("Patch releases", updates["patch_updates"], current_release_license)
        _list_updates(
            "Unknown releases",
            updates["non_semantic_versions"],
            current_release_license,
        )
        has_displayed_updates = True

    if show_pre_releases and updates["pre_releases"]:
        _list_updates("Pre releases", updates["pre_release_updates"], current_release_license)
        has_displayed_updates = True

    if has_displayed_updates:
        print("___")


def _list_updates(update_type, update_list, current_release_license):
    """
    Function used to list package updates by update type in console

    :param update_type: string
    :param update_list: list
    :param current_release_license: string
    """
    if len(update_list):
        print(f"  {update_type}:")
        for update_item in update_list:
            print(
                f"  -- {update_item['version']} on {update_item['upload_time']} - License: {current_release_license}",
            )


def _argument_parser():
    """
    Configure arguments for console
    """
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-f",
        "--file",
        nargs="?",
        type=argparse.FileType(),
        default=None,
        help="Requirements file",
    )
    parser.add_argument(
        "-pr",
        "--pre-releases",
        nargs="?",
        type=_str_to_bool,
        default=False,
        help="Show pre-releases",
    )

    return parser


async def _updatable():
    """
    Function used to output packages update information in the console
    """
    args = _argument_parser().parse_args()

    # Get list of packages
    if args.file:
        packages = updatable_utils.parse_requirements_list(args.file)
    else:
        packages = updatable_utils.get_parsed_environment_package_list()

    # Output updates
    tasks = []
    for package in packages:
        tasks.append(
            asyncio.create_task(_list_package_updates(package["package"], package["version"], args.pre_releases)),
        )

    for task in tasks:
        await task


def main():  # pragma: no cover
    t0 = datetime.datetime.now()
    asyncio.run(_updatable())
    dt = datetime.datetime.now() - t0
    print(f"Done in {dt.total_seconds():.2f} sec.")
