# -*- 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
##
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

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_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)
                    if vnfd and 'monitoring-parameter' in vnfd["vdu"][0]:
                        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)
