#!/usr/bin/python3
# -*- python -*-
"""Collect helpers hook data into a single json file"""

import argparse
import json
import os
import sys
import time

import xdg.BaseDirectory

from gi.repository import GLib
from gi.repository import Gio
from gi.repository import Click

hook_ext = '.json'


def migrate_old_settings():
    old_settings = Gio.Settings.new('com.ubuntu.notifications.hub')
    blacklist = old_settings.get_value('blacklist').unpack()
    if not blacklist:
        return

    old_settings.reset('blacklist')

    for app in blacklist:
        app_key = app[0] + '/'
        if not app[0]:
            app_key = 'dpkg/'
         
        app_key += app[1]

        settings_path = '/com/ubuntu/NotificationSettings/' + app_key + '/'
        settings = Gio.Settings.new_with_path('com.ubuntu.notifications.settings', settings_path)
        settings.set_boolean('enable-notifications', False)


def collect_helpers(helpers_data_path, helpers_data_path_tmp, hooks_path):
    helpers_data = {}
    if not os.path.isdir(hooks_path):
        return True
    for hook_fname in os.listdir(hooks_path):
        if not hook_fname.endswith(hook_ext):
            continue
        try:
            with open(os.path.join(hooks_path, hook_fname), 'r') as fd:
                data = json.load(fd)
        except Exception:
            continue
        else:
            helper_id = os.path.splitext(hook_fname)[0]
            exec_path = data['exec']
            if exec_path != "":
                realpath = os.path.realpath(os.path.join(hooks_path,
                                                         hook_fname))
                exec_path = os.path.join(os.path.dirname(realpath), exec_path)
            app_id = data.get('app_id', None)
            if app_id is None:
                # no app_id, use the package name from the helper_id
                app_id = helper_id.split('_')[0]
            elif app_id.count('_') >= 3:
                # remove the version from the app_id
                app_id = app_id.rsplit('_', 1)[0]
            helpers_data[app_id] = {'exec': exec_path, 'helper_id': helper_id}

    # write the collected data to a temp file and rename the original once
    # everything is on disk
    try:
        tmp_filename = helpers_data_path_tmp % (time.time(),)
        with open(tmp_filename, 'w') as dest:
            json.dump(helpers_data, dest)
            dest.flush()
        os.rename(tmp_filename, helpers_data_path)
    except Exception:
        return True
    return False


def populate_settings_from_legacy_dpkg():
    dpkg_apps_keys = list()
    legacy_helpers_path = '/usr/lib/ubuntu-push-client/legacy-helpers/'
    if os.path.isdir(legacy_helpers_path):
        for f in os.listdir(legacy_helpers_path):
            if not os.path.isfile(os.path.join(legacy_helpers_path, f)):
                break

            dpkg_app_key = '/'.join(['dpkg', f, '0'])
            dpkg_apps_keys.append(dpkg_app_key)

    return dpkg_apps_keys


def reset_settings(path=None):
    if not path:
        return

    settings_path = '/com/ubuntu/NotificationSettings/' + path + '/'
    try:
        settings = Gio.Settings.new_with_path('com.ubuntu.notifications.settings', settings_path)
        for k in settings.list_keys():
            settings.reset(k)
    except Exception:
        pass


def reset_removed_applications(current_apps=None, new_apps=None):
    if not current_apps or not new_apps:
        return

    current_keys = list()
    for k in current_apps:
        key = '/'.join(k.split('/')[:2])
        current_keys.append(key)

    new_keys = list()
    for k in new_apps:
        key = '/'.join(k.split('/')[:2])
        new_keys.append(key)

    for settings_path in set(current_keys) - set(new_keys):
        reset_settings(settings_path)


def populate_notifications_settings(hooks_path=None):
    if not hooks_path or not os.path.isdir(hooks_path):
        return

    db = Click.DB.new()
    db.read()

    settings = Gio.Settings.new('com.ubuntu.notifications.settings.applications')
    applications = GLib.VariantBuilder.new(GLib.VariantType.new('as'))

    current_applications_keys = settings.get_value('applications').unpack()

    applications_keys = list()
    applications_keys += populate_settings_from_legacy_dpkg()
    for hook in os.listdir(hooks_path):
        helper_id = os.path.splitext(hook)[0]
        pkg_name, helper_name, version = helper_id.split('_')

        manifest = json.loads(db.get_manifest_as_string(pkg_name, version))
        hooks = manifest.get('hooks', None)
        if not hooks:
            continue

        app_names = list()
        for h in hooks.keys():
            if 'desktop' in hooks[h].keys():
                app_names.append(h)

        for app_name in app_names:
            app_key = '/'.join([pkg_name, app_name, version])
            applications_keys.append(app_key)

    for app_key in applications_keys:
        applications.add_value(GLib.Variant.new_string(app_key))

    settings.set_value('applications', applications.end())

    reset_removed_applications(current_applications_keys, applications_keys)


def main(helpers_data_path=None, helpers_data_path_tmp=None, hooks_path=None):
    collect_fail = collect_helpers(helpers_data_path, helpers_data_path_tmp,
                                   hooks_path)
    migrate_old_settings_fail = False
    try:
        migrate_old_settings()
    except Exception:
        migrate_old_settings_fail = True

    populate_settings_fail = False
    try:
        populate_notifications_settings(hooks_path)
    except Exception:
        populate_settings_fail = True

    return int(collect_fail or migrate_old_settings_fail or populate_settings_fail)


if __name__ == "__main__":
    xdg_data_home = xdg.BaseDirectory.xdg_data_home
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('-d', '--data-home',
                        help='The Path to the (xdg) data home',
                        default=xdg_data_home)
    args = parser.parse_args()
    xdg_data_home = args.data_home
    helpers_data_path = os.path.join(xdg_data_home, 'ubuntu-push-client',
                                     'helpers_data.json')
    helpers_data_path_tmp = os.path.join(xdg_data_home, 'ubuntu-push-client',
                                         '.helpers_data_%s.tmp')
    hooks_path = os.path.join(xdg_data_home, 'ubuntu-push-client', 'helpers')
    sys.exit(main(helpers_data_path=helpers_data_path,
                  helpers_data_path_tmp=helpers_data_path_tmp,
                  hooks_path=hooks_path))
