#!/usr/bin/python3

import os
import yaml
import click
import subprocess

from urllib.request import urlopen


class colors:
    reset = '\033[0m'
    bold = '\033[01m'
    disable = '\033[02m'
    underline = '\033[04m'
    reverse = '\033[07m'
    strikethrough = '\033[09m'
    invisible = '\033[08m'

    class fg:
        black = '\033[30m'
        red = '\033[31m'
        green = '\033[32m'
        orange = '\033[33m'
        blue = '\033[34m'
        purple = '\033[35m'
        cyan = '\033[36m'
        lightgrey = '\033[37m'
        darkgrey = '\033[90m'
        lightred = '\033[91m'
        lightgreen = '\033[92m'
        yellow = '\033[93m'
        lightblue = '\033[94m'
        pink = '\033[95m'
        lightcyan = '\033[96m'

        rainbow = [lightred, orange, yellow,
                   lightgreen, lightcyan, blue, purple]
        seq = 0

        def random(self):
            if self.seq == 7:
                self.seq = 0
            self.seq += 1
            return self.rainbow[self.seq - 1]

        def clear_seq(self):
            self.seq = 0

    class bg:
        black = '\033[40m'
        red = '\033[41m'
        green = '\033[42m'
        orange = '\033[43m'
        blue = '\033[44m'
        purple = '\033[45m'
        cyan = '\033[46m'
        lightgrey = '\033[47m'


fg = colors.fg()


def info(msg):
    print(colors.bold + fg.cyan + '[INFO] ' +
          colors.reset + msg + colors.reset)


def print_list(msg):
    print(colors.bold + fg.random() + '[LIST] ' +
          colors.reset + msg + colors.reset)


def modrun(msg):
    print(colors.bold + fg.green + '[MODRUN] ' +
          colors.reset + msg + colors.reset)


def container_msg(msg):
    print(colors.bold + fg.purple + '[CONTAINER] ' +
          colors.reset + msg + colors.reset)


def association_msg(msg):
    print(colors.bold + fg.random() + '[ASSOCIATION] ' +
          colors.reset + msg + colors.reset)


def warn(warning):
    print(colors.bold + fg.yellow + '[WARNING] ' +
          colors.reset + warning + colors.reset)


def error(err):
    print(colors.bold + fg.red + '[ERROR] ' +
          colors.reset + err + colors.reset)


def proceed():
    print(colors.bold + fg.red + '[QUESTION] ' +
          colors.reset + 'would you like to proceed?' + colors.reset)
    info(f'(press {colors.bold}ENTER{colors.reset} to proceed, or {colors.bold}^C{colors.reset}/{colors.bold}^D{colors.reset} to cancel)')
    input()


@click.group("cli")
def cli():
    """Manage user operations using the user utility on blendOS."""


def main():
    cli(prog_name="user")


@cli.command("associate")
@click.argument('association')
@click.argument('container')
def associate_binary(association, container):
    '''
    Create an association (for example, apt -> ubuntu)
    '''

    if not os.path.exists(os.path.expanduser(f'~/.local/bin/blend_bin/{association}.{container}')):
        error(f'{colors.bold}{association}.{container}{colors.reset} does not exist')
        exit()
    if os.path.isfile(os.path.expanduser('~/.local/bin/blend_bin/.associations')):
        subprocess.run(['sed', '-i', f's/^{association}\\x0//g',
                       os.path.expanduser('~/.local/bin/blend_bin/.associations')])
    with open(os.path.expanduser('~/.local/bin/blend_bin/.associations'), 'a+') as f:
        f.write(f'{association}\0{container}\n')
    _exists = os.path.exists(os.path.expanduser(
        f'~/.local/bin/blend_bin/{association}'))
    subprocess.run(['ln', '-sf', f'{association}.{container}',
                   os.path.expanduser(f'~/.local/bin/blend_bin/{association}')])
    association_msg(('modified' if _exists else 'created') +
                    f' {colors.bold}{association} -> {container}{colors.reset}')


@cli.command("dissociate")
@click.argument('association')
def associate_binary(association):
    '''
    Remove an association
    '''

    if not os.path.exists(os.path.expanduser(f'~/.local/bin/blend_bin/{association}')):
        error(f'{colors.bold}{association}{colors.reset} does not exist')
        exit()
    if os.path.isfile(os.path.expanduser('~/.local/bin/blend_bin/.associations')):
        subprocess.run(['sed', '-i', f's/^{association}\\x0//g',
                       os.path.expanduser('~/.local/bin/blend_bin/.associations')])
    subprocess.run(
        ['rm', '-f', os.path.expanduser(f'~/.local/bin/blend_bin/{association}')])
    association_msg(f'dissociated {colors.bold}{association}')


@cli.command("create-container")
@click.argument('container_name')
@click.argument('distro', required=False)
def create_container(container_name, distro):
    '''
    Create a container
    '''
    if subprocess.run(['podman', 'container', 'exists', container_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0:
        error(
            f'container {colors.bold}{container_name}{colors.reset} already exists')
        exit(1)
    args = ['blend', 'create-container', '-cn', container_name]
    # blend handles no distro being specified already
    if distro:
        args.extend(['-d', distro])
    exit(subprocess.run(args).returncode)


@cli.command("delete-container")
@click.argument('container')
def delete_container(container):
    '''
    Delete a container
    '''
    if subprocess.run(['podman', 'container', 'exists', container], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0:
        error(
            f'container {colors.bold}{container}{colors.reset} does not exist')
        exit(1)
    subprocess.run(['blend', 'remove-container', container])


@cli.command("shell")
@click.argument('container')
def shell(container):
    '''
    Enter a shell inside a container
    '''
    if subprocess.run(['podman', 'container', 'exists', container], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0:
        error(
            f'container {colors.bold}{container}{colors.reset} does not exist')
        exit(1)
    creation_env = os.environ.copy()
    creation_env['BLEND_NO_CHECK'] = 'true'
    subprocess.run(['blend', 'enter', '-cn', container], env=creation_env)


@cli.command("exec")
@click.argument('container')
@click.argument('cmds', nargs=-1, required=True)
def exec_c(container, cmds):
    '''
    Run a command inside a container
    '''
    if subprocess.run(['podman', 'container', 'exists', container], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0:
        error(
            f'container {colors.bold}{container}{colors.reset} does not exist')
        exit(1)
    creation_env = os.environ.copy()
    creation_env['BLEND_NO_CHECK'] = 'true'
    cmds = [cmd.replace('\\-', '-') for cmd in cmds]
    subprocess.run(['blend', 'enter', '-cn', container,
                   '--', *cmds], env=creation_env)


@cli.command("install")
@click.argument('container')
@click.argument('pkgs', nargs=-1, required=True)
def install_c(container, pkgs):
    '''
    Install a package inside a container
    '''
    if os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/apt.{container}')):
        subprocess.run([f'sudo.{container}', 'apt', 'update'])
        subprocess.run([f'sudo.{container}', 'apt', 'install', *pkgs])
    elif os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/dnf.{container}')):
        subprocess.run([f'sudo.{container}', 'dnf', 'install', *pkgs])
    elif os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/pacman.{container}')):
        subprocess.run([f'sudo.{container}', 'pacman', '-Syu', *pkgs])
    else:
        error(
            f'container {colors.bold}{container}{colors.reset} does not exist')
        exit(1)


@cli.command("remove")
@click.argument('container')
@click.argument('pkgs', nargs=-1, required=True)
def remove_c(container, pkgs):
    '''
    Remove a package inside a container
    '''
    if os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/apt.{container}')):
        subprocess.run([f'sudo.{container}', 'apt', 'purge', *pkgs])
    elif os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/dnf.{container}')):
        subprocess.run([f'sudo.{container}', 'dnf', 'remove', *pkgs])
    elif os.path.isfile(os.path.expanduser(f'~/.local/bin/blend_bin/pacman.{container}')):
        subprocess.run([f'sudo.{container}', 'pacman', '-Rcns', *pkgs])
    else:
        error(
            f'container {colors.bold}{container}{colors.reset} does not exist')
        exit(1)


if __name__ == '__main__':
    main()