#
# Copyright 2018 the original author or authors.
#
# 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.
#
from twisted.internet.defer import returnValue
from pyvoltha.adapters.extensions.omci.omci_defs import *
from voltha.extensions.omci.omci_entities import Ieee8021pMapperServiceProfile
from voltha.extensions.omci.tasks.mib_reconcile_task import MibReconcileTask
from voltha.extensions.omci.database.mib_db_api import ATTRIBUTES_KEY
from twisted.internet.defer import  inlineCallbacks
from voltha.extensions.omci.omci_defs import ReasonCodes, EntityOperations
from voltha.extensions.omci.omci_me import MEFrame

OP = EntityOperations
RC = ReasonCodes
AA = AttributeAccess


class AdtnMibReconcileTask(MibReconcileTask):
    """
    Adtran ONU OpenOMCI MIB Reconcile Task

    For some crazy reason, the ADTRAN ONU does not report the IEEE802.1p Mapper ME
    in the ONU upload even though it does exists.  This results in an 'instance
    exists' error when trying to create it on the ONU
    """
    name = "Adtran MIB Reconcile Task"

    def __init__(self, omci_agent, device_id, diffs):
        super(AdtnMibReconcileTask, self).__init__(omci_agent, device_id, diffs)

        self.name = AdtnMibReconcileTask.name
        self._me_130_okay = False   # Set true once bug is fixed (auto detect)
        self._omci_managed = False  # Set once ONU Data tracking of MIB-Data-Sync supported

    @inlineCallbacks
    def fix_olt_only(self, olt, onu_db, olt_db):
        """
        Fix ME's that were only found on the OLT. For OLT only MEs there are
        the following things that will be checked.

            o ME's that do not have an OpenOMCI class decoder. These are stored
              as binary blobs in the MIB database. Since the OLT will never
              create these (all are learned from ONU), it is assumed the ONU
              has removed them for some purpose. So delete them from the OLT
              database.

            o For ME's that are created by the ONU (no create/delete access), the
              MEs 'may' not be on the ONU because of a reboot or an OLT created
              ME was deleted and the ONU gratuitously removes it.  So delete them
              from the OLT database.

            o For ME's that are created by the OLT/OpenOMCI, delete them from the
              ONU

        :param olt: (list(int,int)) List of tuples where (class_id, inst_id)
        :param onu_db: (dict) ONU Database snapshot at time of audit
        :param olt_db: (dict) OLT Database snapshot at time of audit

        :return: (int, int) successes, failures
        """
        # Has IEEE 802.1p reporting Bug fixed?

        if self._me_130_okay or Ieee8021pMapperServiceProfile.class_id in onu_db:
            self._me_130_okay = True
            returnValue(super(AdtnMibReconcileTask, self).fix_olt_only(olt, onu_db, olt_db))

        ############################
        # Base class handles all but ME 130
        local_mes = {Ieee8021pMapperServiceProfile.class_id}
        not_manual = [(cid, eid) for cid, eid in olt if cid not in local_mes]

        results = yield super(AdtnMibReconcileTask, self).fix_olt_only(not_manual,
                                                                       onu_db,
                                                                       olt_db)
        successes = results[0]
        failures = results[1]

        # If IEEE 802.1p mapper needs to be checked, do it manually as the IBONT 602
        # manipulates it during MEF EVC/EVC-Map creation
        for cid in local_mes:
            class_entry = olt_db.get(cid, None)

            if class_entry is not None:
                entries = {k: v for k, v in class_entry.items() if isinstance(k, int)}
                for eid, instance in entries.items():
                    try:
                        self.strobe_watchdog()
                        results = yield self.manual_verification(cid, eid, instance[ATTRIBUTES_KEY])
                        successes += results[0]
                        failures += results[1]

                    except Exception as _e:
                        failures += 1

        returnValue((successes, failures))

    @inlineCallbacks
    def update_mib_data_sync(self):
        """ IBONT version does not support MDS"""
        if self._omci_managed:
            results = yield super(AdtnMibReconcileTask, self).update_mib_data_sync()
            returnValue(results)

        returnValue((1, 0))

    @inlineCallbacks
    def manual_verification(self, cid, eid, attributes):
        # Trim off read-only attributes from ones passed in

        me_map = self._device.me_map
        ro_set = {AA.R}
        ro_attrs = {attr.field.name for attr in me_map[cid].attributes
                    if attr.access == ro_set}
        attributes = {k: v for k, v in attributes.items() if k not in ro_attrs}
        attributes_to_fix = dict()

        try:
            while len(attributes):
                frame = MEFrame(me_map[cid], eid, attributes).get()
                self.strobe_watchdog()
                results = yield self._device.omci_cc.send(frame)
                omci_message = results.fields['omci_message'].fields
                status = omci_message['success_code']

                if status == RC.UnknownEntity.value:
                    self.strobe_watchdog()
                    results = yield self.create_instance(me_map[cid], eid, attributes)
                    returnValue((results[0], results[1]))

                if status != RC.Success.value:
                    self.log.error('manual-check-get-failed', cid=cid, eid=eid,
                                   attributes=attributes, status=status)
                    returnValue((1, 0))

                onu_attr = {k: v for k, v in omci_message['data'].items()}
                attributes_to_fix.update({k: v for k, v in onu_attr.items()
                                         if k in attributes and v != attributes[k]})
                attributes = {k: v for k, v in attributes if k not in onu_attr.keys()}

            if len(attributes_to_fix) > 0:
                try:
                    frame = MEFrame(me_map[cid], eid, attributes_to_fix).set()
                    self.strobe_watchdog()
                    yield self._device.omci_cc.send(frame)
                    returnValue((1, 0))

                except Exception as _e:
                    returnValue((0, 1))

        except Exception as e:
            self.log.exception('manual-check-failed', e=e, cid=cid, eid=eid)
            raise

    @inlineCallbacks
    def create_instance(self, cid, eid, attributes):
        try:
            me_map = self._device.me_map
            frame = MEFrame(me_map[cid], eid, attributes).create()

            self.strobe_watchdog()
            results = yield self._device.omci_cc.send(frame)
            status = results.fields['omci_message'].fields['success_code']
            if status == RC.Success.value or status == RC.InstanceExists.value:
                returnValue((1, 0))

            self.log.error('manual-check-create-failed', cid=cid, eid=eid,
                           attributes=attributes, status=status)
            returnValue((0, 1))

        except Exception as e:
            self.log.exception('manual-check-failed', e=e, cid=cid, eid=eid)
            raise
