#!/usr/bin/python3
"""Zephir-cmd-input script
"""
from sys import exit, argv
from yaml import load, SafeLoader, YAMLError
from time import sleep
from os.path import isfile

from cucchiaiata import Configuration
from cucchiaiata.common import Common
from cucchiaiata.i18n import _



class Import(Common):
    def __init__(self,
                 config_file: str,
                 ) -> None:
        super().__init__()
        with open(config_file, 'r') as stream:
            try:
                self.config = load(stream,
                                   Loader=SafeLoader,
                                   )
            except YAMLError as err:
                raise Exception(_('unable to lead the YAML file {}').format(err))
        
        self.remote_config = self.remote_json_to_config(self.cucchiaiata_config.remote_url)

    def parse_zones(self) -> None:
        for zone in self.config.get('zones', []):
            self.configuration('infra',
                               'zone',
                               zone,
                               )
            self.send('v1.infra.zone.deploy',
                      zone_name=zone['name'],
                      )

    def parse_clusters(self) -> None:
        for cluster in self.config.get('clusters', []):
            self.configuration('infra',
                               'cluster',
                               cluster,
                               zone_name=cluster['zone'],
                               )
            for node in cluster.get('nodes', []):
                self.configuration('infra',
                                   'cluster.node',
                                   node,
                                   cluster_name=cluster['name'],
                                   zones_name=node['zones'],
                                   )
            self.send('v1.infra.cluster.deploy',
                      cluster_name=cluster['name'],
                      )

    def parse_servermodels(self) -> None:
        for servermodel in self.config.get('servermodels', []):
            self.add_servermodel(servermodel)

    def parse_organizations(self) -> None:
        for organization in self.config.get('organizations', []):
            self.configuration('infra',
                               'organization',
                               organization,
                               )
            for site in organization.get('sites', []):
                self.configuration('infra',
                                   'site',
                                   site,
                                   organization_name=organization['name'],
                                   zones_name=site['zones'],
                                   )
                for server in site.get('servers', []):
                    self.configuration('infra',
                                       'server',
                                       server,
                                       site_name=site['name'],
                                       cluster_name=server['cluster'],
                                       zones_name=server['zones'],
                                       servermodel_name=server['servermodel'],
                                       )
                    self.send('v1.infra.server.deploy',
                              server_name=server['name'],
                              )

    def configuration(self,
                      domain: str,
                      element: str,
                      dico: dict,
                      **kwargs,
                      ) -> None:
        self.upset_element(domain,
                           element,
                           dico['name'],
                           kwargs,
                           )
        if 'settings' in dico:
            #FIXME
            sleep(1)
            self.apply_settings(element,
                                dico,
                                )

    def apply_settings(self,
                       element: str,
                       dico: dict,
                       ) -> None:
        session_id = self.send(f'v1.setting.session.{element}.start',
                               **{f'{element}_name': dico['name']},
                               )['session_id']
        config = Configuration()
        config.message = 'v1.setting.session.configure'
        config.session_id = session_id
        tiramisu = None
        tiramisu_namespace = None
        for key, value in self.settings_paths(dico['settings']):
            current_namespace = key.split('.', 1)[0]
            if tiramisu_namespace != current_namespace:
                if tiramisu is not None:
                    self.send_configuration(tiramisu,
                                            session_id,
                                            )
                tiramisu_namespace = current_namespace
                self.send('v1.setting.session.filter',
                          session_id=session_id,
                          namespace=tiramisu_namespace,
                          )
                tiramisu = config.configure_server()
            try:
                if tiramisu.option(key).option.isfollower():
                    for val in value:
                        tiramisu.option(key, val['index']).value.set(val['value'])
                else:
                    if tiramisu.option(key).option.ismulti() and \
                            not isinstance(value, list):
                        value = [value]
                    tiramisu.option(key).value.set(value)
            except ValueError as err:
                print(_(f'error when setting "{domain}" "{dico["name"]}": "{key}" with value "{value}": {err}'))
                exit(1)
            except Exception as err:
                print(_(f'unexpected error when setting "{domain}" "{dico["name"]}": "{key}" with value "{value}": {err}'))
                exit(1)
        self.send_configuration(tiramisu,
                                session_id,
                                )
        self.send('v1.setting.session.stop',
                  session_id=session_id,
                  save=True,
                  )

    def upset_element(self,
                      domain: str,
                      element: str,
                      name: str,
                      kwargs: dict,
                      ) -> None:
        message_name = element
        if '.' in message_name:
            message_name = message_name.rsplit('.', 1)[-1]
        try:
            self.send(f'v1.{domain}.{element}.describe',
                      **{f'{message_name}_name': name},
                      )
        except:
            # not exists
            print(f'add "{element}" "{name}"')
            kwargs[f'{message_name}_name'] = name
            self.send(f'v1.{domain}.{element}.create',
                      **kwargs,
                      )

    def settings_paths(self,
                       dico: dict,
                       subpath: str=None,
                       ) -> list:
        ret = []
        for key, value in dico.items():
            if subpath:
                key_path = f'{subpath}.{key}'
            else:
                key_path = key
            if isinstance(value, dict):
                ret.extend(self.settings_paths(value, key_path))
            else:
                ret.append((key_path, value))
        return ret

    def add_servermodel(self,
                        servermodel: dict,
                        parents: list=[],
                        ) -> None:
        if 'other_parents' in servermodel:
            parents = parents.copy()
            parents.extend(servermodel['other_parents'])
        self.configuration('setting',
                           'servermodel',
                           servermodel,
                           parents_name=parents,
                           applicationservices_name=servermodel.get('applicationservices', []),
                           )
        if 'children' in servermodel:
            child_parents = parents.copy()
            child_parents.append(servermodel['name'])
            for child in servermodel['children']:
                self.add_servermodel(child,
                                     child_parents,
                                     )


if __name__ == "__main__":
    if len(argv) != 2 or not isfile(argv[1]):
        print(_(f'usage: {argv[0]} filename.yaml'))
        exit(1)
    imp = Import(argv[1])
    imp.parse_zones()
    imp.parse_clusters()
    imp.parse_servermodels()
    imp.parse_organizations()