#    Copyright 2013 - 2017 Mirantis, Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import copy

import reclass
# from reclass.adapters import salt as reclass_salt
from reclass import config as reclass_config
from reclass import core as reclass_core
from reclass import defaults as reclass_defaults
from reclass.datatypes import parameters as reclass_parameters
from reclass.utils.refvalue import RefValue
import yaml
import mock

from reclass_tools import helpers
# import salt.cli.call
# import salt.cli.caller


def refvalue_representer(dumper, data):
    return dumper.represent_str(
        data._assemble(
            lambda s: s.join(reclass_defaults.PARAMETER_INTERPOLATION_SENTINELS)))
yaml.add_representer(RefValue, refvalue_representer)

class ReclassCore(reclass_core.Core):
    """Track the specific key

    :param key: string with dot-separated keys
    """
    track_key_path = None

    def __init__(self, storage, class_mappings, input_data=None,
                 key=None):
        if key:
            if ':' in key:
                # Linux pillar notation:  linux:network:interface
                self.track_key_path = key.split(':')
            else:
                # Python notation: linux.network.interface
                self.track_key_path = key.split('.')

            if self.track_key_path[0] == 'parameters':
                # Remove the first 'parameters' element because the model entities
                # keep parameters in different object format.
                self.track_key_path = self.track_key_path[1:]

        super(ReclassCore, self).__init__(storage, class_mappings, input_data)


    def _recurse_entity(self, entity, merge_base=None, seen=None, nodename=None):

        def _new_merge_dict(self, cur, new, path):
            try:
                return orig_merge_dict(self, cur, new, path)
            except TypeError as e:
                if "Current value:" not in e.message:
                    e.message +="\nValue path: {}\nCurrent value: {}\nNew value: {}\n".format(path, cur, new)
                raise TypeError(e.message)

        if seen is None:
            seen = {}
        if '__visited' not in seen:
            seen['__visited'] = []

        orig_visited = copy.deepcopy(seen['__visited'])
        seen['__visited'].append(entity.name)

        orig_merge_dict = reclass_parameters.Parameters._merge_dict
        with mock.patch.object(reclass_parameters.Parameters, '_merge_dict', new=_new_merge_dict):
            result =  super(ReclassCore, self)._recurse_entity(entity,
                                                               merge_base,
                                                               seen,
                                                               nodename)
        if self.track_key_path:
            key = helpers.get_nested_key(entity.parameters.as_dict(),
                                         path=self.track_key_path)
            if key:
                print("# " + ' < '.join(seen['__visited']))
                out_dict = {}
                helpers.create_nested_key(out_dict, ['parameters'] + self.track_key_path, key)
                print(yaml.dump(out_dict,
                                default_flow_style=False))

        # Reset the data collected by child entries
        seen['__visited'] = orig_visited

        return result

    def _nodeinfo(self, nodename):
        if self.track_key_path:
            print("\n" + nodename)
            print("-" * len(nodename))

        result =  super(ReclassCore, self)._nodeinfo(nodename)

        if self.track_key_path:
            key = helpers.get_nested_key(result.parameters.as_dict(),
                                         path=self.track_key_path)
            if key:
                print("### Final result after interpolation: ###")
                out_dict = {}
                helpers.create_nested_key(out_dict, ['parameters'] + self.track_key_path, key)
                print(yaml.dump(out_dict,
                                default_flow_style=False))
        return result


def get_core(key=None):
    """Initializes reclass Core() using /etc/reclass settings"""

    defaults = reclass_config.find_and_read_configfile()
    inventory_base_uri = defaults['inventory_base_uri']
    storage_type = defaults['storage_type']

    nodes_uri, classes_uri = reclass_config.path_mangler(inventory_base_uri,
                                                         None, None)
    storage = reclass.get_storage(storage_type, nodes_uri, classes_uri,
                                  default_environment='base')

    #key = '_param.keepalived_vip_interface'
    return ReclassCore(storage, None, None, key=key)


# def get_minion_domain():
#     """Try to get domain from the local salt minion"""
#     client = salt.cli.call.SaltCall()
#     client.parse_args(args=['pillar.items'])
#     caller = salt.cli.caller.Caller.factory(client.config)
#     result = caller.call()
#     # Warning! There is a model-related parameter
#     # TODO(ddmitriev): move the path to the parameter to a settings/defaults
#     domain = result['return']['_param']['cluster_domain']
#     return domain


def inventory_list(domain=None):
    core = get_core()
    inventory = core.inventory()['nodes']
    if domain is not None:
        inventory = {key: val for (key, val) in inventory.items()
                     if key.endswith(domain)}
    return inventory


def nodes_list(domain=None):
    core = get_core()
    nodes = core._storage.enumerate_nodes()
    if domain is not None:
        nodes = [node for node in nodes
                 if node.endswith(domain)]
    return nodes


def get_nodeinfo(minion_id):
    core = get_core()
    return core.nodeinfo(minion_id)


def trace_key(key, domain=None, node=None):
    if node:
        nodes = [node]
    else:
        nodes = nodes_list(domain=domain)

    core = get_core(key=key)
    for node in nodes:
        core.nodeinfo(node)


def vcp_list(domain=None, inventory=None):
    """List VCP node names

    Scan all nodes for the object salt.control.cluster.internal.node.XXX.name
    Return set of tuples ((nodename1, domain), (nodename2, domain), ...)
    """

    inventory = inventory or inventory_list(domain=domain)
    vcp_path = 'parameters.salt.control.cluster.internal.node'.split('.')
    domain_path = 'parameters._param.cluster_domain'.split('.')

    vcp_node_names = set()

    for node_name, node in inventory.items():
        vcp_nodes = helpers.get_nested_key(node, path=vcp_path)
        if vcp_nodes is not None:
            for vcp_node_name, vcp_node in vcp_nodes.items():
                vcp_node_names.add((
                    vcp_node['name'],
                    helpers.get_nested_key(node, path=domain_path)))
    return vcp_node_names


def reclass_storage(domain=None, inventory=None):
    """List VCP node names

    Scan all nodes for the object salt.control.cluster.internal.node.XXX.name
    """

    inventory = inventory or inventory_list(domain=domain)
    storage_path = 'parameters.reclass.storage.node'.split('.')

    res = dict()
    for node_name, node in inventory.items():
        storage_nodes = helpers.get_nested_key(node, path=storage_path)
        if storage_nodes is not None:
            for storage_node_name, storage_node in storage_nodes.items():
                if storage_node['domain'] not in res:
                    res[storage_node['domain']] = dict()
                res[storage_node['domain']][storage_node_name] = storage_node
    return res
