#!/usr/bin/env python
"""Script to uninstall AWS CLI V2 Mac PKG"""
import argparse
import sys
import os
import re
from datetime import datetime
from subprocess import check_output
from subprocess import CalledProcessError
from subprocess import PIPE

SCRIPTS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(SCRIPTS_DIR)

from utils import run
from utils import BadRCError


_PKG_ID = 'com.amazon.aws.cli2'
_PKGUTIL_PATTERN = re.compile(
    (
        r'version:\s*(?P<version>.*?)\n'
        r'volume:\s*(?P<volume>.*?)\n'
        r'location:\s*(?P<location>.*?)\n'
        r'install-time:\s*(?P<install_time>.*?)\n'
    ),
    re.X
)

def uninstall():
    assert _is_installed(), 'Could not find AWS CLI installation.'
    assert os.geteuid() == 0, 'Script must be run as root (with sudo).'

    # First we remove all the files listed in the pkg's receipt file,
    # and our own custom metadata file.
    root_dir = _get_root_dir()
    list_files = _get_file_list(root_dir)
    _erase_files(list_files)

    # Once these are all removed the directories should all be empty and can
    # be deleted.
    list_dirs = _get_dir_list(root_dir)
    _erase_dirs(list_dirs)

    # Finally we forget the package receipt.
    _forget()

    print('Successfully uninstalled AWS CLI from %s' % root_dir)
    return 0


def _get_root_dir():
    lines = run('pkgutil --pkg-info %s /' % _PKG_ID, echo=False)
    output = _PKGUTIL_PATTERN.search(lines)
    path = os.path.join(output.group('volume'), output.group('location'))
    return path


def _get_file_list(root):
    lines = run(
        'pkgutil --only-files --files %s /' % _PKG_ID, echo=False).split('\n')
    pkg_file_list = [os.path.join(root, line) for line in lines if line]
    extra_files = _read_install_metadata(root)
    return pkg_file_list + extra_files


def _read_install_metadata(root):
    # Install metadata is a list of files that were installed by helper scripts
    # executed by the PKG. In the AWS CLI V2's case, we use a postinstall
    # script to add binaries symlinks to /usr/bin. These are untracked by the
    # pkg receipt. To track them we add them to a special .install-metdata file
    # in the installer directory.
    metadata_path = os.path.join(root, 'aws-cli', '.install-metadata')
    if not os.path.isfile(metadata_path):
        return []
    extra_files = open(metadata_path, 'r').read()
    return extra_files.split('\n')[:-1]


def _get_dir_list(root):
    lines = run(
        'pkgutil --only-dirs --files %s /' % _PKG_ID, echo=False).split('\n')
    # Longer directory names are listed first to force them to come before
    # their parent directories. This ensures that child directories are
    # deleted before their parents.
    return sorted(
        [os.path.join(root, line) for line in lines if line],
        key=lambda x: -len(x)
    )


def _erase_files(file_list):
    for path in file_list:
        if os.path.isfile(path) or os.path.islink(path):
            os.remove(path)


def _erase_dirs(dir_list):
    for path in dir_list:
        if os.path.isdir(path):
            os.rmdir(path)


def _forget():
    # Forget is the pkgutil command to delete the pkg installer receipt.
    # Once the files have been deleted, the pkgutil command will continue to
    # report that they are installed until the pkg id has been forgotten.
    run('pkgutil --forget %s' % _PKG_ID, echo=False)


def check():
    assert _is_installed(), 'Could not find AWS CLI installation.'

    lines = run('pkgutil --pkg-info %s /' % _PKG_ID, echo=False)
    output = _PKGUTIL_PATTERN.search(lines)
    root = os.path.join(output.group('volume'), output.group('location'))
    print('Found AWS CLI version %s installed at %s' % (
        output.group('version'), root))
    print('Installed on %s' % datetime.fromtimestamp(
        int(output.group('install_time'))))
    command = 'sudo %s uninstall' % os.path.abspath(__file__)
    print('To uninstall run the command:')
    print(command)
    return 0


def _is_installed():
    try:
        result = run('pkgutil --pkg-info %s /' % _PKG_ID, echo=False)
    except BadRCError:
        return False
    return True


def _warn_missing_arg(print_help):

    # wrap `parser.print_help()` to return 1 so any callers don't receive
    # a potentially misleading 0 exit code from a failed call.
    def missing_arg_warning():
        print('Missing input: script requires at least one positional argument\n')
        print_help()
        return 1

    return missing_arg_warning


def main():
    parser = argparse.ArgumentParser(usage=__doc__)
    subparsers = parser.add_subparsers()
    check_parser = subparsers.add_parser(
        'check',
        help=(
            'Check if the AWS CLI is currently installed from a PKG '
            'installer.'
        )
    )
    check_parser.set_defaults(func=check)
    uninstall_parser = subparsers.add_parser(
        'uninstall',
        help='Uninstall the AWS CLI installed from the Mac PKG'
    )
    uninstall_parser.set_defaults(func=uninstall)

    # default to help string if no args are passed
    parser.set_defaults(func=_warn_missing_arg(parser.print_help))

    args = parser.parse_args()
    return args.func()


if __name__ == '__main__':
    try:
        sys.exit(main())
    except AssertionError as e:
        print(e)
        sys.exit(1)
