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

import (
	"context"
	"fmt"

	fu "github.com/opencord/voltha-lib-go/v4/pkg/flows"
	"github.com/opencord/voltha-lib-go/v4/pkg/log"
	ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

// listLogicalDeviceMeters returns logical device meters
func (agent *LogicalAgent) listLogicalDeviceMeters() map[uint32]*ofp.OfpMeterEntry {
	meterIDs := agent.meterLoader.ListIDs()
	meters := make(map[uint32]*ofp.OfpMeterEntry, len(meterIDs))
	for meterID := range meterIDs {
		if meterHandle, have := agent.meterLoader.Lock(meterID); have {
			meters[meterID] = meterHandle.GetReadOnly()
			meterHandle.Unlock()
		}
	}
	return meters
}

// updateMeterTable updates the meter table of that logical device
func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
	logger.Debug(ctx, "updateMeterTable")
	if meterMod == nil {
		return nil
	}
	switch meterMod.GetCommand() {
	case ofp.OfpMeterModCommand_OFPMC_ADD:
		return agent.meterAdd(ctx, meterMod)
	case ofp.OfpMeterModCommand_OFPMC_DELETE:
		return agent.meterDelete(ctx, meterMod)
	case ofp.OfpMeterModCommand_OFPMC_MODIFY:
		return agent.meterModify(ctx, meterMod)
	}
	return status.Errorf(codes.Internal,
		"unhandled-command: logical-device-id:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
}

func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
	if meterMod == nil {
		logger.Errorw(ctx, "failed-meterAdd-meterMod-is-nil", log.Fields{"logical-device-id": agent.logicalDeviceID})
		return nil
	}
	logger.Debugw(ctx, "meterAdd", log.Fields{"metermod": *meterMod, "logical-device-id": agent.logicalDeviceID})

	meterEntry := fu.MeterEntryFromMeterMod(ctx, meterMod)

	meterHandle, created, err := agent.meterLoader.LockOrCreate(ctx, meterEntry)
	if err != nil {
		return err
	}
	defer meterHandle.Unlock()

	if created {
		logger.Debugw(ctx, "Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "logical-device-id": agent.logicalDeviceID})
	} else {
		logger.Infow(ctx, "Meter-already-exists", log.Fields{"meter": *meterMod, "logical-device-id": agent.logicalDeviceID})
	}
	return nil
}

func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
	if meterMod == nil {
		logger.Errorw(ctx, "failed-meterDelete-meterMod-is-nil", log.Fields{"logical-device-id": agent.logicalDeviceID})
		return nil
	}
	logger.Debug(ctx, "meterDelete", log.Fields{"meterMod": *meterMod, "logical-device-id": agent.logicalDeviceID})

	meterHandle, have := agent.meterLoader.Lock(meterMod.MeterId)
	if !have {
		logger.Warnw(ctx, "meter-not-found", log.Fields{"meterID": meterMod.MeterId, "logical-device-id": agent.logicalDeviceID})
		return nil
	}
	defer meterHandle.Unlock()

	//TODO: A meter lock is held here while flow lock(s) are acquired, if this is done in opposite order anywhere
	//      there's potential for deadlock.
	if err := agent.deleteFlowsHavingMeter(ctx, meterMod.MeterId); err != nil {
		return err
	}

	if err := meterHandle.Delete(ctx); err != nil {
		return err
	}

	logger.Debugw(ctx, "meterDelete-success", log.Fields{"meterID": meterMod.MeterId, "logical-device-id": agent.logicalDeviceID})
	return nil
}

func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
	logger.Debug(ctx, "meterModify")
	if meterMod == nil {
		logger.Errorw(ctx, "failed-meterModify-meterMod-is-nil", log.Fields{"logical-device-id": agent.logicalDeviceID})
		return nil
	}

	meterHandle, have := agent.meterLoader.Lock(meterMod.MeterId)
	if !have {
		return fmt.Errorf("no-meter-to-modify: %d, logical-device-id: %s", meterMod.MeterId, agent.logicalDeviceID)
	}
	defer meterHandle.Unlock()

	oldMeter := meterHandle.GetReadOnly()
	newMeter := fu.MeterEntryFromMeterMod(ctx, meterMod)
	newMeter.Stats.FlowCount = oldMeter.Stats.FlowCount

	if err := meterHandle.Update(ctx, newMeter); err != nil {
		return err
	}
	logger.Debugw(ctx, "replaced-with-new-meter", log.Fields{"oldMeter": oldMeter, "newMeter": newMeter, "logical-device-id": agent.logicalDeviceID})
	return nil
}
