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

# Copyright 2021 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.core.keystone import KeystoneConnection
from osm_mon.dashboarder.backends.grafana import GrafanaBackend
from osm_mon import __path__ as mon_path
from osm_mon.core.utils import find_in_list, create_filter_from_nsr

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)

        if bool(self.conf.get('keystone', 'enabled')):
            self.keystone = KeystoneConnection(self.conf)
        else:
            self.keystone = None

    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 = []
        projects = []

        # Check if keystone is the auth/projects backend and get projects from there
        if self.keystone:
            try:
                projects.extend(
                    map(lambda project: {'_id': project.id, 'name': project.name}, self.keystone.getProjects())
                )
            except Exception:
                log.error('Cannot retrieve projects from keystone')

        # Reads existing project list and creates a dashboard for each
        projects.extend(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']
                if project_name != "admin":
                    # Create project folder in Grafana only if user is not admin.
                    # Admin user's dashboard will be created in default folder
                    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'], create_filter_from_nsr(nsr))
                    # 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]
                            try:
                                # Get project details from commondb
                                project_details = self.common_db.get_project(project_id)
                                project_name = project_details["name"]
                            except Exception as e:
                                # Project not found in commondb
                                if self.keystone:
                                    # Serach project in keystone
                                    for project in projects:
                                        if project_id == project['_id']:
                                            project_name = project["name"]
                                else:
                                    log.info('Project %s not found', project_id)
                                    log.debug('Exception %s' % e)
                            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):
        try:
            # Get user details from  commondb
            user = self.common_db.get_user_by_id(userid)
            user_name = user["username"]
        except Exception as e:
            # User not found in commondb
            if self.keystone:
                # Serach user in keystone
                user = self.keystone.getUserById(userid)
                user_name = user.name
            else:
                log.info('User %s not found', userid)
                log.debug('Exception %s' % e)
        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)
