import hashlib
import json
import os
import sys
from collections import OrderedDict
from subprocess import check_call, check_output

# WARNING: changing those affects reproducibility
GO_ROOT = '/tmp/go'
GO_PATH = '/tmp/go-path'

NDK_DIR = 'android-ndk'


def get_version():
    if len(sys.argv) > 2:
        fail("Usage: %s [version tag]" % sys.argv[0])
    return sys.argv[1] if len(sys.argv) > 1 else None


def get_version_and_tool():
    if len(sys.argv) < 2 or len(sys.argv) > 3:
        fail("Usage: %s tool [version tag]" % sys.argv[0])
    tool = sys.argv[1]
    command_line_version = sys.argv[2] if len(sys.argv) > 2 else None
    return tool, command_line_version


def get_build_versions(tool, tag):
    # load versions and their dependencies
    with open('versions.json', 'r') as f:
        versions = json.load(f, object_pairs_hook=OrderedDict)

    if tag is None:
        # take top-most version
        tag = next(iter(versions[tool]))
    return tag, versions[tool][tag]


def check_go_version(versions):
    # Check if proper Go version is installed (trailing space, because 'go1.10' in 'go1.10.1')
    if versions['go']['version'] + ' ' not in check_output(['go', 'version']).decode("UTF-8"):
        fail("You need Go version %s to reproduce this binary" % versions['go']['version'])


def ex(args, env=None, cwd=None):
    print("+ %s" % " ".join(args))
    check_call(args, env=env, cwd=cwd)


def fail(msg=""):
    sys.stderr.write("Error: %s\n" % msg)
    sys.exit(1)


def get_sha256(filename, block_size=65536):
    sha256 = hashlib.sha256()
    with open(filename, 'rb') as f:
        for block in iter(lambda: f.read(block_size), b''):
            sha256.update(block)
    return sha256.hexdigest()


def reset_time(file_name):
    check_call(['touch', '--no-dereference', '-t', '197001010000.00', file_name])


def zip_files(files, zip_name):
    for file_name in files:
        reset_time(file_name)
        # use deterministic permissions to prevent differences in zip files
        os.chmod(file_name, 0o755)
        sha256hash = get_sha256(file_name)
        print("Hash before zipping %s: %s" % (file_name, sha256hash))
    ex(['zip', '-D', '-X', zip_name] + files)


def get_obfs4_version(versions):
    version = versions['revision']
    if '-' in version:
        return version.split('-')[1]
    return version


def get_file_suffix(versions, android=False):
    version = get_obfs4_version(versions)
    return "%s-%s" % ("android", version) if android else version


def get_final_file_name(versions, android=False):
    return 'obfs4proxy-%s.zip' % get_file_suffix(versions, android)


def get_sources_file_name(versions, android=False):
    return 'obfs4proxy-%s-sources.jar' % get_file_suffix(versions, android)


def get_pom_file_name(versions, android=False):
    return 'obfs4proxy-%s.pom' % get_file_suffix(versions, android)