'''
OSX target, based on kivy-sdk-packager
'''

import sys
if sys.platform != 'darwin':
    raise NotImplementedError('This will only work on osx')

from buildozer.target import Target
from os.path import exists, join, abspath, dirname
from subprocess import check_call, check_output


class TargetOSX(Target):
    targetname = "osx"

    def ensure_sdk(self):
        self.buildozer.info('Check if kivy-sdk-packager exists')
        if exists(
                join(self.buildozer.platform_dir, 'kivy-sdk-packager-master')):
            self.buildozer.info(
                    'kivy-sdk-packager found at '
                '{}'.format(self.buildozer.platform_dir))
            return

        self.buildozer.info('kivy-sdk-packager does not exist, clone it')
        platdir = self.buildozer.platform_dir
        check_call(
            ('curl', '-O', '-L',
            'https://github.com/kivy/kivy-sdk-packager/archive/master.zip'),
            cwd=platdir)
        check_call(('unzip', 'master.zip'), cwd=platdir)
        check_call(('rm', 'master.zip'), cwd=platdir)

    def download_kivy(self, cwd, py_branch=2):
        current_kivy_vers = self.buildozer.config.get('app', 'osx.kivy_version')

        if exists('/Applications/Kivy{}.app'.format(py_branch)):
            self.buildozer.info('Kivy found in Applications dir...')
            check_call(
                ('cp', '-a', '/Applications/Kivy{}.app'.format(py_branch),
                'Kivy.app'), cwd=cwd)

        else:
            if not exists(join(cwd, 'Kivy{}.dmg'.format(py_branch))):
                self.buildozer.info('Downloading kivy...')
                status_code = check_output(
                    ('curl', '-L', '--write-out', '%{http_code}', '-o', 'Kivy{}.dmg'.format(py_branch),
                    'https://kivy.org/downloads/{}/Kivy-{}-osx-python{}.dmg'
                    .format(current_kivy_vers, current_kivy_vers, py_branch)),
                    cwd=cwd)

                if status_code == "404":
                    self.buildozer.error(
                        "Unable to download the Kivy App. Check osx.kivy_version in your buildozer.spec, and verify "
                        "Kivy servers are accessible. https://kivy.org/downloads/")
                    check_call(("rm", "Kivy{}.dmg".format(py_branch)), cwd=cwd)
                    sys.exit(1)

            self.buildozer.info('Extracting and installing Kivy...')
            check_call(('hdiutil', 'attach', cwd + '/Kivy{}.dmg'.format(py_branch)))
            check_call(('cp', '-a', '/Volumes/Kivy/Kivy.app', './Kivy.app'), cwd=cwd)

    def ensure_kivyapp(self):
        self.buildozer.info('check if Kivy.app exists in local dir')
        kivy_app_dir = join(self.buildozer.platform_dir, 'kivy-sdk-packager-master', 'osx')

        py_branch = self.buildozer.config.get('app', 'osx.python_version')

        if not int(py_branch) in (2, 3):
            self.buildozer.error('incompatible python version... aborting')
            sys.exit(1)

        if exists(join(kivy_app_dir, 'Kivy.app')):
            self.buildozer.info('Kivy.app found at ' + kivy_app_dir)
        else:
            self.download_kivy(kivy_app_dir, py_branch)

    def check_requirements(self):
        self.ensure_sdk()
        self.ensure_kivyapp()

    def check_configuration_tokens(self, errors=None):
        if errors:
            self.buildozer.info('Check target configuration tokens')
            self.buildozer.error(
                '{0} error(s) found in the buildozer.spec'.format(
                len(errors)))
            for error in errors:
                print(error)
            sys.exit(1)
        # check

    def build_package(self):
        self.buildozer.info('Building package')

        bc = self.buildozer.config
        bcg = bc.get
        package_name = bcg('app', 'package.name')
        domain = bcg('app', 'package.domain')
        title = bcg('app', 'title')
        app_deps = open('requirements.txt').read()
        icon = bc.getdefault('app', 'icon.filename', '')
        version = self.buildozer.get_version()
        author = bc.getdefault('app', 'author', '')

        self.buildozer.info('Create {}.app'.format(package_name))
        cwd = join(self.buildozer.platform_dir, 'kivy-sdk-packager-master', 'osx')
        # remove kivy from app_deps
        app_deps = [a for a in app_deps.split('\n') if not a.startswith('#') and a not in ['kivy', '']]

        cmd = [
            'Kivy.app/Contents/Resources/script',
             '-m', 'pip', 'install',
             ]
        cmd.extend(app_deps)
        check_output(cmd, cwd=cwd)

        cmd = [
            'python', 'package_app.py', self.buildozer.app_dir,
            '--appname={}'.format(package_name),
             '--bundlename={}'.format(title),
             '--bundleid={}'.format(domain),
             '--bundleversion={}'.format(version),
             '--displayname={}'.format(title)
             ]
        if icon:
            cmd.append('--icon={}'.format(icon))
        if author:
            cmd.append('--author={}'.format(author))

        check_output(cmd, cwd=cwd)

        self.buildozer.info('{}.app created.'.format(package_name))
        self.buildozer.info('Creating {}.dmg'.format(package_name))
        check_output(
            ('sh', '-x', 'create-osx-dmg.sh', package_name + '.app'),
            cwd=cwd)
        self.buildozer.info('{}.dmg created'.format(package_name))
        self.buildozer.info('moving {}.dmg to bin.'.format(package_name))
        binpath = join(
            self.buildozer.user_build_dir or
            dirname(abspath(self.buildozer.specfilename)), 'bin')
        check_output(
            ('cp', '-a', package_name + '.dmg', binpath),
            cwd=cwd)
        self.buildozer.info('All Done!')

    def compile_platform(self):
        pass

    def install_platform(self):
        # ultimate configuration check.
        # some of our configuration cannot be check without platform.
        self.check_configuration_tokens()
        #
        self.buildozer.environ.update({
            'PACKAGES_PATH': self.buildozer.global_packages_dir,
        })

    def get_custom_commands(self):
        result = []
        for x in dir(self):
            if not x.startswith('cmd_'):
                continue
            if x[4:] in self.buildozer.standard_cmds:
                continue
            result.append((x[4:], getattr(self, x).__doc__))
        return result

    def get_available_packages(self):
        return ['kivy']

    def run_commands(self, args):
        if not args:
            self.buildozer.error('Missing target command')
            self.buildozer.usage()
            sys.exit(1)

        result = []
        last_command = []
        for arg in args:
            if not arg.startswith('--'):
                if last_command:
                    result.append(last_command)
                    last_command = []
                last_command.append(arg)
            else:
                if not last_command:
                    self.buildozer.error('Argument passed without a command')
                    self.buildozer.usage()
                    sys.exit(1)
                last_command.append(arg)
        if last_command:
            result.append(last_command)

        config_check = False

        for item in result:
            command, args = item[0], item[1:]
            if not hasattr(self, 'cmd_{0}'.format(command)):
                self.buildozer.error('Unknown command {0}'.format(command))
                sys.exit(1)

            func = getattr(self, 'cmd_{0}'.format(command))

            need_config_check = not hasattr(func, '__no_config')
            if need_config_check and not config_check:
                config_check = True
                self.check_configuration_tokens()

            func(args)

    def check_build_prepared(self):
        self._build_prepared = False

    def cmd_clean(self, *args):
        self.buildozer.clean_platform()

    def cmd_update(self, *args):
        self.platform_update = True
        self.buildozer.prepare_for_build()

    def cmd_debug(self, *args):
        self.buildozer.prepare_for_build()
        self.build_mode = 'debug'
        self.check_build_prepared()
        self.buildozer.build()

    def cmd_release(self, *args):
        self.buildozer.prepare_for_build()
        self.build_mode = 'release'
        self.buildozer.build()

    def cmd_deploy(self, *args):
        self.buildozer.prepare_for_build()

    def cmd_run(self, *args):
        self.buildozer.prepare_for_build()

    def cmd_serve(self, *args):
        self.buildozer.cmd_serve()


def get_target(buildozer):
    return TargetOSX(buildozer)