/*
 * Copyright 2018-present Open Networking Foundation

 * 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.
 */

package core

import (
	"strconv"

	pb "github.com/opencord/voltha-bbsim/api"
	"github.com/opencord/voltha-bbsim/common/logger"
	"github.com/opencord/voltha-bbsim/device"
	openolt "github.com/opencord/voltha-protos/go/openolt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

const (
	// OnuLossOfPloam is state on onu los
	OnuLossOfPloam = "lossofploam"
	// OnuLossOfOmciChannel is the state on omci channel loss alarm
	OnuLossOfOmciChannel = "lossofomcichannel"
	// OnuSignalDegrade is the state on signal degrade alarm
	OnuSignalDegrade = "signaldegrade"
	// AlarmOn is for raising the alarm
	AlarmOn = "on"
	// AlarmOff is for clearing the alarm
	AlarmOff = "off"
)

func (s *Server) handleOnuAlarm(in *pb.ONUAlarmRequest) (*pb.BBSimResponse, error) {
	value, ok := s.SNmap.Load(in.OnuSerial)
	onu := value.(*device.Onu)
	if !ok {
		return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, "no active or discovered onu found with serial number "+in.OnuSerial)
	}

	if (onu.InternalState == device.ONU_LOS_RAISED || onu.InternalState == device.ONU_LOS_ON_OLT_PON_LOS) &&
		(in.AlarmType != OnuLossOfPloam) {
		return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, in.OnuSerial+" is not reachable, can not send onu alarm")
	}

	if s.Olt.PonIntfs[onu.IntfID].AlarmState == device.PonLosRaised && (in.AlarmType != OnuLossOfPloam) {
		// Don't send onu alarm as OLT-PON is down
		return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, "pon-port down, can not send onu alarm")
	}
	switch in.AlarmType {
	case OnuLossOfOmciChannel:
		Ind := formulateLossOfOmciChannelAlarm(in.Status, onu)
		if in.Status == AlarmOn {
			onu.UpdateIntState(device.ONU_OMCI_CHANNEL_LOS_RAISED)
		} else {
			onu.UpdateIntState(device.ONU_ACTIVE)
		}
		s.alarmCh <- Ind
		return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil

	case OnuSignalDegrade:
		Ind := formulateSignalDegradeAlarm(in.Status, onu)
		s.alarmCh <- Ind
		return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil

	case OnuLossOfPloam:
		if in.Status == AlarmOn {
			onu.UpdateIntState(device.ONU_LOS_RAISED)
			device.UpdateOnusOpStatus(onu.IntfID, onu, "down")
		} else {
			onu.UpdateIntState(device.ONU_ACTIVE)
			device.UpdateOnusOpStatus(onu.IntfID, onu, "up")
			// TODO is it required to check onu state?
			err := sendOnuDiscInd(*s.EnableServer, onu)
			if err != nil {
				logger.Error("Error: %v", err.Error())
			}
		}
		Ind := formulateLossOfPLOAM(in.Status, onu)
		s.alarmCh <- Ind
		er := sendOnuInd(*s.EnableServer, onu, onu.OperState, "up")
		if er != nil {
			logger.Debug(er.Error())
		}

		resp, err := s.checkAndSendOltPonLos(in.OnuSerial, in.Status, device.IntfPon) // Send olt los if all the onus attached to a pon-port shows los
		if err != nil {
			return resp, err
		}
		return resp, nil

	default:
		logger.Debug("Unhandled alarm type")
		return &pb.BBSimResponse{}, status.Errorf(codes.Unimplemented, "Unhandled alarm type")
	}

}

func (s *Server) handleOltAlarm(in *pb.OLTAlarmRequest) (*pb.BBSimResponse, error) {
	switch in.PortType {
	case device.IntfNni:

		if !s.isNniIntfPresentInOlt(in.PortId) {
			return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, strconv.Itoa(int(in.PortId))+" NNI not present in olt")
		}

		Ind := formulateOLTLOSAlarm(in.Status, in.PortId, device.IntfNni)
		s.alarmCh <- Ind
		s.setNNIPortState(in.PortId, in.Status)

	case device.IntfPon:
		if !s.isPonIntfPresentInOlt(in.PortId) {
			return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, strconv.Itoa(int(in.PortId))+" PON not present in olt")
		}
		Ind := formulateOLTLOSAlarm(in.Status, in.PortId, in.PortType)
		s.alarmCh <- Ind
		onusOperstat := s.setPONPortState(in.PortId, in.Status)
		for _, onu := range s.Onumap[in.PortId] {
			if onu.InternalState == device.ONU_LOS_RAISED || onu.InternalState == device.ONU_FREE {
				continue // Skip for onus which have independently raised onu los
			}

			er := sendOnuInd(*s.EnableServer, onu, onusOperstat, "up")
			if er != nil {
				logger.Debug(er.Error())
			}
			s.sendOnuLosOnOltPonLos(onu, in.Status)
		}
	default:
		return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "invalid interface type provided")
	}

	return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
}

func (s *Server) setNNIPortState(portID uint32, alarmstatus string) {
	switch alarmstatus {
	case AlarmOn:
		s.Olt.UpdateNniPortState(portID, device.NniLosRaised, "down")

	case AlarmOff:
		s.Olt.UpdateNniPortState(portID, device.NniLosCleared, "up")
	}
}

func (s *Server) setPONPortState(portID uint32, alarmstatus string) string {
	switch alarmstatus {
	case AlarmOn:
		s.Olt.UpdatePonPortState(portID, device.PonLosRaised, "down")
		return "down"

	case AlarmOff:
		s.Olt.UpdatePonPortState(portID, device.PonLosCleared, "up")
		return "up"
	}
	return ""
}

func (s *Server) sendOnuLosOnOltPonLos(onu *device.Onu, status string) {
	var internalState device.DeviceState

	if status == AlarmOn {
		internalState = device.ONU_LOS_ON_OLT_PON_LOS
	} else if status == AlarmOff {
		internalState = device.ONU_ACTIVE
	}

	Ind := formulateLossOfPLOAM(status, onu)
	onu.UpdateIntState(internalState)

	// update onus slice on alarm off
	if status == "off" {
		err := sendOnuDiscInd(*s.EnableServer, onu)
		if err != nil {
			logger.Error(err.Error())
		}
	}

	s.alarmCh <- Ind
}

func formulateLossOfOmciChannelAlarm(status string, onu *device.Onu) *openolt.Indication {
	logger.Debug("formulateLossofOmciChannelAlarm() invoked")

	alarmIndication := &openolt.AlarmIndication_OnuLossOmciInd{
		OnuLossOmciInd: &openolt.OnuLossOfOmciChannelIndication{
			IntfId: onu.IntfID,
			OnuId:  onu.OnuID,
			Status: status,
		},
	}

	alarmind := &openolt.AlarmIndication{
		Data: alarmIndication,
	}

	msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind}
	Ind := &openolt.Indication{Data: msg}
	return Ind
}

func formulateSignalDegradeAlarm(status string, onu *device.Onu) *openolt.Indication {
	logger.Debug("formulateSignalDegrade() invoked")
	alarmIndication := &openolt.AlarmIndication_OnuSignalDegradeInd{
		OnuSignalDegradeInd: &openolt.OnuSignalDegradeIndication{
			IntfId:              onu.IntfID,
			OnuId:               onu.OnuID,
			Status:              status,
			InverseBitErrorRate: 0,
		},
	}
	alarmind := &openolt.AlarmIndication{
		Data: alarmIndication,
	}
	msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind}
	Ind := &openolt.Indication{Data: msg}
	return Ind
}

func formulateLossOfPLOAM(status string, onu *device.Onu) *openolt.Indication {
	logger.Debug("formulateLossOfPLOAM() invoked")

	alarmIndication := &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{
		IntfId:             onu.IntfID,
		OnuId:              onu.OnuID,
		LosStatus:          status,
		LobStatus:          status,
		LopcMissStatus:     status,
		LopcMicErrorStatus: status,
	}}

	alarmind := &openolt.AlarmIndication{Data: alarmIndication}
	msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind}
	Ind := &openolt.Indication{Data: msg}
	return Ind
}

func formulateOLTLOSAlarm(status string, PortID uint32, intfType string) *openolt.Indication {
	intfID := interfaceIDToPortNo(PortID, intfType)

	alarmIndication := &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{
		IntfId: intfID,
		Status: status,
	}}

	alarmind := &openolt.AlarmIndication{Data: alarmIndication}
	msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind}
	Ind := &openolt.Indication{Data: msg}
	return Ind
}

func (s *Server) checkAndSendOltPonLos(serial string, status string, intfType string) (*pb.BBSimResponse, error) {
	value, _ := s.SNmap.Load(serial)
	onu := value.(*device.Onu)
	if s.getNoOfActiveOnuByPortID(onu.IntfID) == 0 {
		logger.Warn("Warning: Sending OLT-LOS, as all onus on pon-port %v raised los", onu.IntfID)
		request := &pb.OLTAlarmRequest{PortId: onu.IntfID, Status: AlarmOn, PortType: device.IntfPon}
		resp, err := s.handleOltAlarm(request)
		return resp, err
	}
	if s.Olt.PonIntfs[onu.IntfID].AlarmState == device.PonLosRaised && status == AlarmOff {
		s.setPONPortState(onu.IntfID, status)
		Ind := formulateOLTLOSAlarm(status, onu.IntfID, intfType)
		s.alarmCh <- Ind
	}

	return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil
}

func interfaceIDToPortNo(intfid uint32, intfType string) uint32 {
	// Converts interface-id to port-numbers that can be understood by the voltha
	if intfType == device.IntfNni {
		// nni at voltha starts with 65536
		// nni = 65536 + interface_id
		return 0x1<<16 + intfid
	} else if intfType == device.IntfPon {
		// pon = 536,870,912 + interface_id
		return (0x2 << 28) + intfid // In openolt code, stats_collection.cc line number 196, pon starts from 0
		// In bbsim, pon starts from 1
	}
	return 0
}
