/*
 * 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-bbsim/protos"
	"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
}
