#    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):
            try:
                result =  super(ReclassCore, self)._recurse_entity(entity,
                                                                   merge_base,
                                                                   seen,
                                                                   nodename)
            except Exception:
                print("### Interpolation failed in the class: " + ' < '.join(seen['__visited']))
                raise
        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
