/*
 * 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 (
	"net"

	"gerrit.opencord.org/voltha-bbsim/common/logger"
	"gerrit.opencord.org/voltha-bbsim/device"
	flowHandler "gerrit.opencord.org/voltha-bbsim/flow"
	openolt "gerrit.opencord.org/voltha-bbsim/protos"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	omci "github.com/opencord/omci-sim"
	log "github.com/sirupsen/logrus"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// DisableOlt method sends OLT down indication
func (s *Server) DisableOlt(c context.Context, empty *openolt.Empty) (*openolt.Empty, error) {
	logger.Debug("OLT receives DisableOLT()")

	err := flowHandler.PortDown(0)
	if err != nil {
		logger.Error("Failed in port down %v", err)
	}

	if s.EnableServer != nil {
		if err := sendOltIndDown(*s.EnableServer); err != nil {
			return new(openolt.Empty), err
		}
		logger.Debug("Successfuly sent OLT DOWN indication")
	}
	return new(openolt.Empty), nil
}

// ReenableOlt method sends OLT up indication for re-enabling OLT
func (s *Server) ReenableOlt(c context.Context, empty *openolt.Empty) (*openolt.Empty, error) {
	logger.Debug("OLT receives Reenable()")

	err := flowHandler.PortUp(0)
	if err != nil {
		logger.Error("Failed in port up %v", err)
	}

	if s.EnableServer != nil {
		if err := sendOltIndUp(*s.EnableServer, s.Olt); err != nil {
			logger.Error("Failed to send OLT UP indication for reenable OLT: %v", err)
			return new(openolt.Empty), err
		}
		logger.Debug("Successfuly sent OLT UP indication")
	}
	return new(openolt.Empty), nil
}

// CollectStatistics method invoked by VOLTHA to get OLT statistics
func (s *Server) CollectStatistics(c context.Context, empty *openolt.Empty) (*openolt.Empty, error) {
	logger.Debug("OLT receives CollectStatistics()")
	return new(openolt.Empty), nil
}

// GetDeviceInfo returns OLT info
func (s *Server) GetDeviceInfo(c context.Context, empty *openolt.Empty) (*openolt.DeviceInfo, error) {
	logger.Debug("OLT receives GetDeviceInfo()")
	devinfo := new(openolt.DeviceInfo)
	devinfo.Vendor = "EdgeCore"
	devinfo.Model = "asfvolt16"
	devinfo.HardwareVersion = ""
	devinfo.FirmwareVersion = ""
	devinfo.Technology = "xgspon"
	devinfo.PonPorts = 16
	devinfo.OnuIdStart = 1
	devinfo.OnuIdEnd = 255
	devinfo.AllocIdStart = 1024
	devinfo.AllocIdEnd = 16383
	devinfo.GemportIdStart = 1024
	devinfo.GemportIdEnd = 65535
	devinfo.FlowIdStart = 1
	devinfo.FlowIdEnd = 16383
	devinfo.DeviceSerialNumber = s.Olt.SerialNumber

	return devinfo, nil
}

// ActivateOnu method handles ONU activation request from VOLTHA
func (s *Server) ActivateOnu(c context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
	logger.Debug("OLT receives ActivateONU()")

	matched, exist := s.getOnuFromSNmap(onu.SerialNumber)
	if !exist {
		logger.Fatal("ONU not found with serial nnumber %v", onu.SerialNumber)
		return new(openolt.Empty), status.Errorf(codes.NotFound, "ONU not found with serial number %v", onu.SerialNumber)
	}
	onuid := onu.OnuId
	matched.OnuID = onuid
	s.updateDevIntState(matched, device.ONU_ACTIVE)
	logger.Debug("ONU IntfID: %d OnuID: %d activated succesufully.", onu.IntfId, onu.OnuId)
	if err := sendOnuInd(*s.EnableServer, matched, s.IndInterval, "up", "up"); err != nil {
		logger.Error("Failed to send ONU Indication intfID %d, onuID %d", matched.IntfID, matched.OnuID)
		return new(openolt.Empty), err
	}

	return new(openolt.Empty), nil
}

// CreateTconts method should handle Tcont creation
func (s *Server) CreateTconts(c context.Context, tconts *openolt.Tconts) (*openolt.Empty, error) {
	logger.Debug("OLT receives CreateTconts()")
	return new(openolt.Empty), nil
}

// RemoveTconts method should handle t-cont removal
func (s *Server) RemoveTconts(c context.Context, tconts *openolt.Tconts) (*openolt.Empty, error) {
	logger.Debug("OLT receives RemoveTconts()")
	return new(openolt.Empty), nil
}

// DeactivateOnu method should handle ONU deactivation
func (s *Server) DeactivateOnu(c context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
	logger.Debug("OLT receives DeactivateONU()")
	return new(openolt.Empty), nil
}

// DeleteOnu handles ONU deletion request from VOLTHA
func (s *Server) DeleteOnu(c context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
	logger.Debug("OLT receives DeleteONU() intfID: %d, onuID: %d", onu.IntfId, onu.OnuId)
	Onu, err := s.GetOnuByID(onu.OnuId, onu.IntfId)
	if err != nil {
		return new(openolt.Empty), err
	}

	// Mark ONU internal state as ONU_FREE and reset onuID
	Onu.InternalState = device.ONU_FREE
	Onu.OnuID = 0

	// Get snMap key for the ONU serial number
	snkey := stringifySerialNumber(Onu.SerialNumber)

	// Delete Serial number entry from SNmap
	logger.Info("Deleting serial number %s from SNmap", snkey)
	s.SNmap.Delete(snkey)
	return new(openolt.Empty), nil
}

func (s *Server) GetOnuInfo(c context.Context, onu *openolt.Onu) (*openolt.OnuIndication, error) {
	logger.Debug("Olt receives GetOnuInfo() intfID: %d, onuID: %d", onu.IntfId, onu.OnuId)
	Onu, err := s.GetOnuByID(onu.OnuId, onu.IntfId)
	if err != nil {
		logger.Error("ONU not found intfID %d, onuID %d", onu.IntfId, onu.OnuId)
		return new(openolt.OnuIndication), err
	}
	onuIndication := new(openolt.OnuIndication)
	onuIndication.IntfId = Onu.IntfID
	onuIndication.OnuId = Onu.OnuID
	onuIndication.OperState = Onu.OperState

	return onuIndication, nil
}

// OmciMsgOut receives OMCI messages from voltha
func (s *Server) OmciMsgOut(c context.Context, msg *openolt.OmciMsg) (*openolt.Empty, error) {
	logger.Debug("OLT %d receives OmciMsgOut to IF %v (ONU-ID: %v) pkt:%x.", s.Olt.ID, msg.IntfId, msg.OnuId, msg.Pkt)
	// Get ONU state
	onu, err := s.GetOnuByID(msg.OnuId, msg.IntfId)
	if err != nil {
		logger.Error("ONU not found intfID %d, onuID %d", msg.IntfId, msg.OnuId)
		return new(openolt.Empty), err
	}
	state := onu.GetIntState()
	logger.Debug("ONU-ID: %v, ONU state: %d", msg.OnuId, state)

	// If ONU is ONU_INACTIVE, ONU_FREE or ONU_OMCI_CHANNEL_LOS_RAISED drop
	if state != device.ONU_ACTIVE && state != device.ONU_OMCIACTIVE {
		logger.Info("ONU (IF %v ONU-ID: %v) is not ACTIVE, so not processing OmciMsg", msg.IntfId, msg.OnuId)
		return new(openolt.Empty), nil
	}
	s.omciOut <- *msg
	return new(openolt.Empty), nil
}

func (s *Server) OnuPacketOut(c context.Context, packet *openolt.OnuPacket) (*openolt.Empty, error) {
	onu, err := s.GetOnuByID(packet.OnuId, packet.IntfId)
	if err != nil {
		logger.Error("Failed in OnuPacketOut, %v", err)
		return new(openolt.Empty), err
	}
	device.LoggerWithOnu(onu).Debugf("OLT %d receives OnuPacketOut () to IF-ID:%d ONU-ID %d.", s.Olt.ID, packet.IntfId, packet.OnuId)
	onuid := packet.OnuId
	intfid := packet.IntfId
	rawpkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
	if err := s.onuPacketOut(intfid, onuid, rawpkt); err != nil {
		device.LoggerWithOnu(onu).WithField("error", err).Errorf("OnuPacketOut Error ")
		return new(openolt.Empty), err
	}
	return new(openolt.Empty), nil
}

func (s *Server) UplinkPacketOut(c context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
	logger.Debug("OLT %d receives UplinkPacketOut().", s.Olt.ID)
	rawpkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
	if err := s.uplinkPacketOut(rawpkt); err != nil {
		return new(openolt.Empty), err
	}
	return new(openolt.Empty), nil
}

// FlowAdd method should handle flows addition to datapath for OLT and ONU
func (s *Server) FlowAdd(c context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
	logger.Debug("OLT %d receives FlowAdd() %v", s.Olt.ID, flow)
	// Check if flow already present
	flowKey := FlowKey{
		FlowID:        flow.FlowId,
		FlowDirection: flow.FlowType,
	}
	if _, exist := s.FlowMap[flowKey]; exist {
		logger.Error("Flow already exists %v", flow)
		return new(openolt.Empty), status.Errorf(codes.AlreadyExists, "Flow already exists")
	}

	// Send flow to flowHandler
	err := flowHandler.AddFlow(flow)
	if err != nil {
		logger.Error("Error in pushing flow to datapath")
		return new(openolt.Empty), err
	}

	// Update flowMap
	s.FlowMap[flowKey] = flow

	onu, err := s.GetOnuByID(uint32(flow.OnuId), uint32(flow.AccessIntfId))
	if err == nil {
		onu.GemportID = uint16(flow.GemportId)

		device.LoggerWithOnu(onu).WithFields(log.Fields{
			"olt":   s.Olt.ID,
			"c_tag": flow.Action.IVid,
		}).Debug("OLT receives FlowAdd().")


		// EAPOL flow
		if flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) {
			logger.WithFields(log.Fields{
				"Classifier.OVid": flow.Classifier.OVid,
				"Classifier.IVid": flow.Classifier.IVid,
				"Classifier.EthType": flow.Classifier.EthType,
				"Classifier.SrcPort": flow.Classifier.SrcPort,
				"Classifier.DstPort": flow.Classifier.DstPort,
				"Action.OVid": flow.Action.OVid,
				"Action.IVid": flow.Action.IVid,
				"IntfID": flow.AccessIntfId,
				"OltID": s.Olt.ID,
				"OnuID": flow.OnuId,
				"FlowId": flow.FlowId,
				"UniID": flow.UniId,
				"PortNo": flow.PortNo,
				"FlowType": flow.FlowType,
			}).Debug("OLT receives EAPOL flow")

			if flow.Classifier.OVid == 4091 {
				omcistate := omci.GetOnuOmciState(onu.IntfID, onu.OnuID)
				if omcistate != omci.DONE {
					logger.Warn("FlowAdd() OMCI state %d is not \"DONE\"", omci.GetOnuOmciState(onu.OnuID, onu.IntfID))
				}
				_ = s.updateOnuIntState(onu.IntfID, onu.OnuID, device.ONU_OMCIACTIVE)
			}

		}

		// DHCP flow
		if flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) {
			logger.Debug("Received flow's srcPort:%d dstPort:%d", flow.Classifier.SrcPort, flow.Classifier.DstPort)
			if flow.Classifier.SrcPort == uint32(68) && flow.Classifier.DstPort == uint32(67) {
				logger.Debug("OLT %d receives DHCP flow IntfID:%d OnuID:%d EType:%x GemPortID:%d VLanIDs: %d/%d",
					s.Olt.ID, flow.AccessIntfId, flow.OnuId, flow.Classifier.EthType, flow.GemportId, flow.Classifier.OVid, flow.Classifier.IVid)
				omcistate := omci.GetOnuOmciState(onu.IntfID, onu.OnuID)
				if omcistate != omci.DONE {
					logger.Warn("FlowAdd() OMCI state %d is not \"DONE\"", omci.GetOnuOmciState(onu.OnuID, onu.IntfID))
				}
				_ = s.updateOnuIntState(onu.IntfID, onu.OnuID, device.ONU_AUTHENTICATED)
			}
		}
		// Update flow ID in ONU object
		onu.FlowIDs = append(onu.FlowIDs, flow.FlowId)
	}
	return new(openolt.Empty), nil
}

// FlowRemove handles flow deletion from datapath
func (s *Server) FlowRemove(c context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
	logger.Debug("OLT %d receives FlowRemove(): %v", s.Olt.ID, flow)

	// Check if flow exists
	flowKey := FlowKey{
		FlowID:        flow.FlowId,
		FlowDirection: flow.FlowType,
	}
	if _, exist := s.FlowMap[flowKey]; !exist {
		logger.Error("Flow %v not found", flow)
		return new(openolt.Empty), status.Errorf(codes.NotFound, "Flow not found")
	}

	flow = s.FlowMap[flowKey]
	// Send delete flow to flowHandler
	err := flowHandler.DeleteFlow(flow)
	if err != nil {
		return new(openolt.Empty), err
	}

	onu, err := s.GetOnuByID(uint32(flow.OnuId), uint32(flow.AccessIntfId))
	if err != nil {
		logger.Warn("Failed flow remove %v", err)
	} else {
		// Delete flowID from onu
		onu.DeleteFlowID(flow.FlowId)
		device.LoggerWithOnu(onu).WithFields(log.Fields{
			"olt":   s.Olt.ID,
			"c_tag": flow.Action.IVid,
		}).Debug("OLT receives FlowRemove().")
		logger.Debug("Flows %v in ONU %d", onu.FlowIDs, onu.OnuID)
	}

	// Delete flow from flowMap
	delete(s.FlowMap, flowKey)

	return new(openolt.Empty), nil
}

func (s *Server) HeartbeatCheck(c context.Context, empty *openolt.Empty) (*openolt.Heartbeat, error) {
	logger.Debug("OLT %d receives HeartbeatCheck().", s.Olt.ID)
	signature := new(openolt.Heartbeat)
	signature.HeartbeatSignature = s.Olt.HeartbeatSignature
	return signature, nil
}

func (s *Server) EnablePonIf(c context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
	logger.Debug("OLT %d receives EnablePonIf().", s.Olt.ID)
	return new(openolt.Empty), nil
}

func (s *Server) GetPonIf(c context.Context, intf *openolt.Interface) (*openolt.IntfIndication, error) {
	logger.Debug("OLT %d receives GetPonIf().", s.Olt.ID)
	stat := new(openolt.IntfIndication)

	if intf.IntfId > (s.Olt.NumPonIntf - 1) {
		logger.Error("PON ID %d out of bounds. %d ports total", intf.IntfId, s.Olt.NumPonIntf)
		return stat, status.Errorf(codes.OutOfRange, "PON ID %d out of bounds. %d ports total (indexing starts at 0)", intf.IntfId, s.Olt.NumPonIntf)
	}
	stat.IntfId = intf.IntfId
	stat.OperState = s.Olt.PonIntfs[intf.IntfId].OperState
	return stat, nil

}

func (s *Server) DisablePonIf(c context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
	logger.Debug("OLT %d receives DisablePonIf().", s.Olt.ID)
	return new(openolt.Empty), nil
}

// Reboot method handles reboot of OLT
func (s *Server) Reboot(c context.Context, empty *openolt.Empty) (*openolt.Empty, error) {
	logger.Debug("OLT %d receives Reboot ().", s.Olt.ID)
	// Initialize OLT & Env
	logger.Debug("Initialized by Reboot")
	s.handleOLTReboot()
	return new(openolt.Empty), nil
}

// EnableIndication starts sending indications for OLT and ONU
func (s *Server) EnableIndication(empty *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
	logger.Debug("OLT receives EnableInd.")
	defer func() {
		logger.Debug("grpc EnableIndication Done")
	}()
	if err := s.Enable(&stream); err != nil {
		logger.Error("Failed to Enable Core: %v", err)
		return err
	}
	return nil
}

// NewGrpcServer starts openolt gRPC server
func NewGrpcServer(addrport string) (l net.Listener, g *grpc.Server, e error) {
	logger.Debug("OpenOLT gRPC server listening %s ...", addrport)
	g = grpc.NewServer()
	l, e = net.Listen("tcp", addrport)
	return
}
