# -*- coding: utf-8 -*-

# Copyright 2018 Whitestack, LLC
# *************************************************************

# This file is part of OSM Monitoring module
# All Rights Reserved to Whitestack, LLC

# 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.
# For those usages not covered by the Apache License, Version 2.0 please
# contact: glavado@whitestack.com or fbravo@whitestack.com
##
import logging

from osm_mon.core.common_db import CommonDbClient
from osm_mon.core.config import Config
from osm_mon.dashboarder.backends.grafana import GrafanaBackend
from osm_mon import __path__ as mon_path
from osm_mon.dashboarder.utils import find_in_list

log = logging.getLogger(__name__)


class DashboarderService:
    def __init__(self, config: Config):
        self.conf = config
        self.common_db = CommonDbClient(self.conf)
        self.grafana = GrafanaBackend(self.conf)

    def create_dashboards(self):
        # TODO lavado: migrate these methods to mongo change streams
        # Lists all dashboards and OSM resources for later comparisons
        dashboard_uids = self.grafana.get_all_dashboard_uids()
        osm_resource_uids = []

        # Reads existing project list and creates a dashboard for each
        projects = self.common_db.get_projects()
        for project in projects:
            project_id = project['_id']
            # Collect Project IDs for periodical dashboard clean-up
            osm_resource_uids.append(project_id)
            dashboard_path = '{}/dashboarder/templates/project_scoped.json'.format(mon_path[0])
            if project_id not in dashboard_uids:
                project_name = project['name']
                self.grafana.create_grafana_folders(project_name)
                self.grafana.create_dashboard(project_id, project_name,
                                              dashboard_path)
                log.debug('Created dashboard for Project: %s', project_id)
            else:
                log.debug('Dashboard already exists')

        # Reads existing NS list and creates a dashboard for each
        # TODO lavado: only create for ACTIVE NSRs
        nsrs = self.common_db.get_nsrs()
        for nsr in nsrs:
            nsr_id = nsr['_id']
            dashboard_path = '{}/dashboarder/templates/ns_scoped.json'.format(mon_path[0])
            # Collect NS IDs for periodical dashboard clean-up
            osm_resource_uids.append(nsr_id)
            # Check if the NSR's VNFDs contain metrics
            # Only one DF at the moment, support for this feature is comming in the future
            vnfds_profiles = nsr['nsd']["df"][0]['vnf-profile']
            for vnf_profile in vnfds_profiles:
                try:
                    vnfd = self.common_db.get_vnfd_by_id(vnf_profile['vnfd-id'])
                    # If there are metrics, create dashboard (if exists)
                    vdu_found = find_in_list(vnfd["vdu"], lambda a_vdu: "monitoring-parameter" in a_vdu)
                    if vdu_found:
                        if nsr_id not in dashboard_uids:
                            nsr_name = nsr['name']
                            project_id = nsr["_admin"]["projects_read"][0]
                            project_details = self.common_db.get_project(project_id)
                            project_name = project_details["name"]
                            self.grafana.create_dashboard(nsr_id, nsr_name,
                                                          dashboard_path, project_name)
                            log.debug('Created dashboard for NS: %s', nsr_id)
                        else:
                            log.debug('Dashboard already exists')
                        break
                    else:
                        log.debug('NS does not has metrics')
                except Exception:
                    log.exception("VNFD is not valid or has been renamed")
                    continue

        # Delete obsolete dashboards
        for dashboard_uid in dashboard_uids:
            if dashboard_uid not in osm_resource_uids:
                self.grafana.delete_dashboard(dashboard_uid)
                log.debug('Deleted obsolete dashboard: %s', dashboard_uid)
            else:
                log.debug('All dashboards in use')

    def create_grafana_user(self, user):
        self.grafana.create_grafana_users(user)

    def create_grafana_team_member(self, project_data, userid):
        user = self.common_db.get_user_by_id(userid)
        user_name = user["username"]
        proj_list = []
        for project in project_data:
            proj_list.append(project["project"])
        for proj in project_data:
            role_obj = self.common_db.get_role_by_name(proj["role"])
            is_admin = role_obj["permissions"].get("admin")
            self.grafana.create_grafana_teams_members(proj["project"], user_name, is_admin, proj_list)

    def create_grafana_team(self, team_name):
        self.grafana.create_grafana_teams(team_name)

    def delete_grafana_user(self, user_name):
        self.grafana.delete_grafana_users(user_name)

    def delete_grafana_team(self, project_name):
        self.grafana.delete_grafana_team(project_name)

    def update_grafana_team(self, project_new_name, project_old_name):
        self.grafana.update_grafana_teams(project_new_name, project_old_name)
