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

        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'])
                    # 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)
