import os
import subprocess
import json
import urllib.request
from mule.util import os_util
from mule.util import file_util
from mule.util import time_util
from mule.util import s3_util
from mule.util import semver_util
import platform

def build_algo_release_url(package_type, channel, os_type, cpu_arch_type, package_version):
    return f"https://algorand-releases.s3.amazonaws.com/channel/{channel}/{package_type}_{channel}_{os_type}-{cpu_arch_type}_{package_version}.tar.gz"

def get_latest_package_version(package_type, channel, os_type, cpu_arch_type):
    os_type = os_util.get_os_type()
    cpu_arch_type = os_util.get_cpu_arch_type()
    package_keys = list(s3_util.get_matching_s3_keys(
        'algorand-releases',
        f"channel/{channel}/{package_type}_{channel}_{os_type}-{cpu_arch_type}_",
        'tar.gz',
        s3_auth=False
    ))
    package_versions = list(map(semver_util.parse_version, package_keys))
    latest_version = semver_util.get_highest_version(package_versions)
    print(f"Found latest version of package type {package_type} for channel {channel}: {latest_version}")
    return latest_version

def install_node(data_dir, bin_dir, channel, node_package_version='latest'):
    """
    Download and install algod.
    """
    node_package_dir = file_util.ensure_folder(f"/tmp/algod-pkg-{time_util.get_timestamp()}")
    data_dir = file_util.ensure_folder(data_dir)
    bin_dir = file_util.ensure_folder(bin_dir)

    os_type = os_util.get_os_type()
    cpu_arch_type = os_util.get_cpu_arch_type()

    if node_package_version == 'latest':
        if channel == 'test':
            node_package_version = get_latest_package_version('node', 'stable', os_type, cpu_arch_type)
        else:
            node_package_version = get_latest_package_version('node', channel, os_type, cpu_arch_type)

    print(f"Installing {channel} node package version {node_package_version} to:\n\tbin_dir: {bin_dir}\n\tdata_dir: {data_dir}")

    node_package_url = build_algo_release_url('node', channel, os_type, cpu_arch_type, node_package_version)
    if channel == 'test':
        node_package_url = build_algo_release_url('node', 'stable', os_type, cpu_arch_type, node_package_version)
    node_package_tar_path = f"{node_package_dir}/node_package.tar.gz"

    _ = urllib.request.urlretrieve(node_package_url, node_package_tar_path)
    file_util.decompressTarfile(node_package_tar_path, f"{node_package_dir}")

    file_util.mv_folder_contents(f"{node_package_dir}/data", data_dir)
    file_util.mv_folder_contents(f"{node_package_dir}/bin", bin_dir)
    if channel == 'stable':
        file_util.copy_file(
            os.path.join(node_package_dir, "genesis/mainnet/genesis.json"),
            os.path.join(data_dir, 'genesis.json')
        )
    else:
        file_util.copy_file(
            os.path.join(node_package_dir, f"genesis/{channel}net/genesis.json"),
            os.path.join(data_dir, 'genesis.json')
        )

def show_node_configs(data_dir, kmd_dir):
    data_dir = file_util.ensure_folder(data_dir)
    kmd_dir = file_util.ensure_folder(kmd_dir)
    node_config_path = f"{data_dir}/config.json"
    kmd_config_path = f"{kmd_dir}/kmd_config.json"

    file_util.ensure_file(node_config_path, '{}')
    file_util.ensure_file(kmd_config_path, '{}')

    current_node_config = file_util.read_json_file(node_config_path)
    current_kmd_config = file_util.read_json_file(kmd_config_path)

    print(f"Showing node configs at {node_config_path} with:\n{json.dumps(current_node_config, sort_keys=True, indent=4)}")
    print(f"Showing node configs at {kmd_config_path} with:\n{json.dumps(current_kmd_config, sort_keys=True, indent=4)}")

def configure_node(data_dir, kmd_dir, node_config, kmd_config):

    data_dir = file_util.ensure_folder(data_dir)
    kmd_dir = file_util.ensure_folder(kmd_dir)
    node_config_path = f"{data_dir}/config.json"
    kmd_config_path = f"{kmd_dir}/kmd_config.json"

    file_util.ensure_file(node_config_path, '{}')
    file_util.ensure_file(kmd_config_path, '{}')

    current_node_config = file_util.read_json_file(node_config_path)
    current_kmd_config = file_util.read_json_file(kmd_config_path)

    current_node_config.update(node_config)
    current_kmd_config.update(kmd_config)

    print(f"Updating node configs at {node_config_path} with:\n{json.dumps(node_config, sort_keys=True, indent=4)}")
    print(f"Updating node configs at {kmd_config_path} with:\n{json.dumps(kmd_config, sort_keys=True, indent=4)}")

    file_util.write_json_file(node_config_path, current_node_config)
    file_util.write_json_file(kmd_config_path, current_kmd_config)

def start_node(data_dir, kmd_dir, bin_dir=None):
    goal_args = [
        'node',
        'start',
    ]
    print(f"Starting node with:\n\tdata_dir: {data_dir}\n\tkmd_dir: {kmd_dir}")
    goal(data_dir, kmd_dir, goal_args, bin_dir)

def stop_node(data_dir, kmd_dir, bin_dir=None):
    goal_args = [
        'node',
        'stop',
    ]
    print(f"Stopping node with:\n\tdata_dir: {data_dir}\n\tkmd_dir: {kmd_dir}")
    goal(data_dir, kmd_dir, goal_args, bin_dir)

def restart_node(data_dir, kmd_dir, bin_dir=None):
    goal_args = [
        'node',
        'restart',
    ]
    print(f"Restarting node with:\n\tdata_dir: {data_dir}\n\tkmd_dir: {kmd_dir}")
    goal(data_dir, kmd_dir, goal_args, bin_dir)

def status_node(data_dir, kmd_dir, bin_dir=None):
    goal_args = [
        'node',
        'status',
    ]
    print(f"Status of node with:\n\tdata_dir: {data_dir}\n\tkmd_dir: {kmd_dir}")
    goal(data_dir, kmd_dir, goal_args, bin_dir)

def goal(data_dir, kmd_dir, args, bin_dir=None):
    goal_command = ['goal']
    if not bin_dir is None:
        goal_command = [f"{bin_dir}/goal"]

    goal_command.extend([
        '-d', data_dir,
        '-k', kmd_dir,
    ])
    goal_command.extend(args)

    subprocess.run(goal_command, check=True)

def algorand_indexer(args, bin_dir=None, log_file_name=None):
    algorand_indexer_command = ['algorand-indexer']
    if not bin_dir is None:
        algorand_indexer_command = [f"{bin_dir}/algorand-indexer"]
    if log_file_name is None:
        log_file_name = f"indexer-{time_util.get_timestamp()}.log"

    algorand_indexer_command.extend(args)
    log_file = open(log_file_name, 'w')
    subprocess.Popen(algorand_indexer_command, stdout=log_file, stderr=log_file)

def start_indexer_local_node(node, postgres, bin_dir=None, pid_file=None, log_file_name=None):
    algorand_indexer_args = ['daemon']

    algorand_indexer_args.extend([
        '-d', node['data'],
        '--postgres', build_indexer_postgress_connection_string(postgres)
    ])

    if not pid_file is None:
        algorand_indexer_args.extend([
            '--pidfile', pid_file
        ])

    algorand_indexer(algorand_indexer_args, bin_dir, log_file_name)

def start_indexer_remote_node(node, postgres, bin_dir=None, pid_file=None, log_file_name=None):
    algorand_indexer_args = ['daemon']

    algorand_indexer_args.extend([
        '--algod-net', f"{node['host']}:{node['port']}",
        '--algod-token', node['token'],
        '--genesis', node['genesis'],
        '--postgres', build_indexer_postgress_connection_string(postgres)
    ])

    if not pid_file is None:
        algorand_indexer_args.extend([
            '--pidfile', pid_file
        ])

    algorand_indexer(algorand_indexer_args, bin_dir, log_file_name)

def build_indexer_postgress_connection_string(postgres):
    postgress_connection_string = []
    for field in postgres.items():
        postgress_connection_string.append(f"{field[0]}={field[1]}")
    return ' '.join(postgress_connection_string)

[((16, 14, 16, 35), 'mule.util.os_util.get_os_type', 'os_util.get_os_type', ({}, {}), '()', False, 'from mule.util import os_util\n'), ((17, 20, 17, 47), 'mule.util.os_util.get_cpu_arch_type', 'os_util.get_cpu_arch_type', ({}, {}), '()', False, 'from mule.util import os_util\n'), ((25, 21, 25, 70), 'mule.util.semver_util.get_highest_version', 'semver_util.get_highest_version', ({(25, 53, 25, 69): 'package_versions'}, {}), '(package_versions)', False, 'from mule.util import semver_util\n'), ((34, 15, 34, 48), 'mule.util.file_util.ensure_folder', 'file_util.ensure_folder', ({(34, 39, 34, 47): 'data_dir'}, {}), '(data_dir)', False, 'from mule.util import file_util\n'), ((35, 14, 35, 46), 'mule.util.file_util.ensure_folder', 'file_util.ensure_folder', ({(35, 38, 35, 45): 'bin_dir'}, {}), '(bin_dir)', False, 'from mule.util import file_util\n'), ((37, 14, 37, 35), 'mule.util.os_util.get_os_type', 'os_util.get_os_type', ({}, {}), '()', False, 'from mule.util import os_util\n'), ((38, 20, 38, 47), 'mule.util.os_util.get_cpu_arch_type', 'os_util.get_cpu_arch_type', ({}, {}), '()', False, 'from mule.util import os_util\n'), ((54, 4, 54, 77), 'mule.util.file_util.decompressTarfile', 'file_util.decompressTarfile', ({(54, 32, 54, 53): 'node_package_tar_path', (54, 55, 54, 76): 'f"""{node_package_dir}"""'}, {}), "(node_package_tar_path, f'{node_package_dir}')", False, 'from mule.util import file_util\n'), ((56, 4, 56, 70), 'mule.util.file_util.mv_folder_contents', 'file_util.mv_folder_contents', ({(56, 33, 56, 59): 'f"""{node_package_dir}/data"""', (56, 61, 56, 69): 'data_dir'}, {}), "(f'{node_package_dir}/data', data_dir)", False, 'from mule.util import file_util\n'), ((57, 4, 57, 68), 'mule.util.file_util.mv_folder_contents', 'file_util.mv_folder_contents', ({(57, 33, 57, 58): 'f"""{node_package_dir}/bin"""', (57, 60, 57, 67): 'bin_dir'}, {}), "(f'{node_package_dir}/bin', bin_dir)", False, 'from mule.util import file_util\n'), ((70, 15, 70, 48), 'mule.util.file_util.ensure_folder', 'file_util.ensure_folder', ({(70, 39, 70, 47): 'data_dir'}, {}), '(data_dir)', False, 'from mule.util import file_util\n'), ((71, 14, 71, 46), 'mule.util.file_util.ensure_folder', 'file_util.ensure_folder', ({(71, 38, 71, 45): 'kmd_dir'}, {}), '(kmd_dir)', False, 'from mule.util import file_util\n'), ((75, 4, 75, 49), 'mule.util.file_util.ensure_file', 'file_util.ensure_file', ({(75, 26, 75, 42): 'node_config_path', (75, 44, 75, 48): '"""{}"""'}, {}), "(node_config_path, '{}')", False, 'from mule.util import file_util\n'), ((76, 4, 76, 48), 'mule.util.file_util.ensure_file', 'file_util.ensure_file', ({(76, 26, 76, 41): 'kmd_config_path', (76, 43, 76, 47): '"""{}"""'}, {}), "(kmd_config_path, '{}')", False, 'from mule.util import file_util\n'), ((78, 26, 78, 68), 'mule.util.file_util.read_json_file', 'file_util.read_json_file', ({(78, 51, 78, 67): 'node_config_path'}, {}), '(node_config_path)', False, 'from mule.util import file_util\n'), ((79, 25, 79, 66), 'mule.util.file_util.read_json_file', 'file_util.read_json_file', ({(79, 50, 79, 65): 'kmd_config_path'}, {}), '(kmd_config_path)', False, 'from mule.util import file_util\n'), ((86, 15, 86, 48), 'mule.util.file_util.ensure_folder', 'file_util.ensure_folder', ({(86, 39, 86, 47): 'data_dir'}, {}), '(data_dir)', False, 'from mule.util import file_util\n'), ((87, 14, 87, 46), 'mule.util.file_util.ensure_folder', 'file_util.ensure_folder', ({(87, 38, 87, 45): 'kmd_dir'}, {}), '(kmd_dir)', False, 'from mule.util import file_util\n'), ((91, 4, 91, 49), 'mule.util.file_util.ensure_file', 'file_util.ensure_file', ({(91, 26, 91, 42): 'node_config_path', (91, 44, 91, 48): '"""{}"""'}, {}), "(node_config_path, '{}')", False, 'from mule.util import file_util\n'), ((92, 4, 92, 48), 'mule.util.file_util.ensure_file', 'file_util.ensure_file', ({(92, 26, 92, 41): 'kmd_config_path', (92, 43, 92, 47): '"""{}"""'}, {}), "(kmd_config_path, '{}')", False, 'from mule.util import file_util\n'), ((94, 26, 94, 68), 'mule.util.file_util.read_json_file', 'file_util.read_json_file', ({(94, 51, 94, 67): 'node_config_path'}, {}), '(node_config_path)', False, 'from mule.util import file_util\n'), ((95, 25, 95, 66), 'mule.util.file_util.read_json_file', 'file_util.read_json_file', ({(95, 50, 95, 65): 'kmd_config_path'}, {}), '(kmd_config_path)', False, 'from mule.util import file_util\n'), ((103, 4, 103, 68), 'mule.util.file_util.write_json_file', 'file_util.write_json_file', ({(103, 30, 103, 46): 'node_config_path', (103, 48, 103, 67): 'current_node_config'}, {}), '(node_config_path, current_node_config)', False, 'from mule.util import file_util\n'), ((104, 4, 104, 66), 'mule.util.file_util.write_json_file', 'file_util.write_json_file', ({(104, 30, 104, 45): 'kmd_config_path', (104, 47, 104, 65): 'current_kmd_config'}, {}), '(kmd_config_path, current_kmd_config)', False, 'from mule.util import file_util\n'), ((149, 4, 149, 44), 'subprocess.run', 'subprocess.run', (), '', False, 'import subprocess\n'), ((160, 4, 160, 80), 'subprocess.Popen', 'subprocess.Popen', (), '', False, 'import subprocess\n'), ((18, 24, 23, 5), 'mule.util.s3_util.get_matching_s3_keys', 's3_util.get_matching_s3_keys', (), '', False, 'from mule.util import s3_util\n'), ((60, 12, 60, 74), 'os.path.join', 'os.path.join', ({(60, 25, 60, 41): 'node_package_dir', (60, 43, 60, 73): '"""genesis/mainnet/genesis.json"""'}, {}), "(node_package_dir, 'genesis/mainnet/genesis.json')", False, 'import os\n'), ((61, 12, 61, 50), 'os.path.join', 'os.path.join', ({(61, 25, 61, 33): 'data_dir', (61, 35, 61, 49): '"""genesis.json"""'}, {}), "(data_dir, 'genesis.json')", False, 'import os\n'), ((65, 12, 65, 80), 'os.path.join', 'os.path.join', ({(65, 25, 65, 41): 'node_package_dir', (65, 43, 65, 79): 'f"""genesis/{channel}net/genesis.json"""'}, {}), "(node_package_dir, f'genesis/{channel}net/genesis.json')", False, 'import os\n'), ((66, 12, 66, 50), 'os.path.join', 'os.path.join', ({(66, 25, 66, 33): 'data_dir', (66, 35, 66, 49): '"""genesis.json"""'}, {}), "(data_dir, 'genesis.json')", False, 'import os\n'), ((33, 65, 33, 90), 'mule.util.time_util.get_timestamp', 'time_util.get_timestamp', ({}, {}), '()', False, 'from mule.util import time_util\n'), ((81, 63, 81, 120), 'json.dumps', 'json.dumps', (), '', False, 'import json\n'), ((82, 62, 82, 118), 'json.dumps', 'json.dumps', (), '', False, 'import json\n'), ((100, 64, 100, 113), 'json.dumps', 'json.dumps', (), '', False, 'import json\n'), ((101, 63, 101, 111), 'json.dumps', 'json.dumps', (), '', False, 'import json\n'), ((156, 35, 156, 60), 'mule.util.time_util.get_timestamp', 'time_util.get_timestamp', ({}, {}), '()', False, 'from mule.util import time_util\n')]