from gzip          import compress
from urllib.parse  import quote
from pkg_resources import resource_string
from json          import loads, dumps
from collections   import OrderedDict


def res_plain(resource):
    """Returns package data as plain bytes"""
    return resource_string(__name__, resource)

def res_gzip(resource):
    """Returns package data as gzipped bytes"""
    return compress(res_plain(resource))

# Reusable data from static files
files = {
    # systemd units
    'coremeta'                  : res_plain('data/systemd/coreos-metadata.service.d/10-provider.conf'),
    'coremetassh'               : res_plain('data/systemd/coreos-metadata-sshkeys@.service.d/10-provider.conf'),
    'kubelet'                   : res_plain('data/systemd/kubelet.service'),
    'etcd'                      : res_plain('data/systemd/etcd-member.service.d/10-daemon.conf'),
    'docker'                    : res_plain('data/systemd/docker.service.d/10-daemon.conf'),
    # k8s components manifests
    'apiserver'                 : res_plain('data/k8s/manifests/kube-apiserver.json'),
    'proxy'                     : res_plain('data/k8s/manifests/kube-proxy.json'),
    'controller-manager'        : res_plain('data/k8s/manifests/kube-controller-manager.json'),
    'scheduler'                 : res_plain('data/k8s/manifests/kube-scheduler.json'),
    'addon-manager'             : res_gzip('data/k8s/manifests/kube-addon-manager.yml'),
    # k8s components config
    'kubelet-config'            : res_gzip('data/k8s/kubeletconfig.json'),
    'proxy-config'              : res_gzip('data/k8s/kubeproxyconfig.json'),
    'controller-manager-config' : res_gzip('data/k8s/kubecontrollermanagerconfig.json'),
    'scheduler-config'          : res_gzip('data/k8s/kubeschedulerconfig.json'),
    # k8s addons manifests
    'kubedns'                   : res_gzip('data/k8s/addons/kubedns.yml'),
    'flannel'                   : res_gzip('data/k8s/addons/flannel.yml'),
    # k8s kubeconfig
    'kubeconfig'                : res_plain('data/k8s/kubeconfig.json')
}


class UserData:

    def __init__(self, k8s_ver='1.12.2'):
        self.k8s_ver = k8s_ver

        # boilerplate ignition config
        self.data = {
            'ignition': { 'version': '2.1.0' },
            'storage': {},
            'systemd': {}
        }

    def add_files(self, definition):
        """Add elements to node storage['files']"""

        if not 'files' in self.data['storage']:
            self.data['storage']['files'] = []

        if isinstance(definition, list):
            self.data['storage']['files'].extend(definition)
        else:
            raise TypeError("'definition must be a list, not '{}'".format(type(definition)))

    def add_sunits(self, definition):
        """Add elements to node systemd['units']"""

        if not 'units' in self.data['systemd']:
            self.data['systemd']['units'] = []

        if isinstance(definition, list):
            self.data['systemd']['units'].extend(definition)
        else:
            raise TypeError("'definition must be a list, not '{}'".format(type(definition)))

    def configure_clinux_core(self):
        """Generate drop-ins for Container Linux core services"""

        self.add_sunits([
            {
                'name': 'coreos-metadata.service',
                'dropins': [{
                    'name': '10-provider.conf',
                    'contents': files['coremeta'].decode()
                }]
            },
            {
                'name': 'coreos-metadata-sshkeys@.service',
                'enable': True,
                'dropins': [{
                    'name': '10-provider.conf',
                    'contents': files['coremetassh'].decode()