/*
 * 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 mocks provides the mocks for openolt-adapter.
package mocks

import (
	"context"
	"errors"
	"fmt"

	"github.com/opencord/voltha-lib-go/v3/pkg/kafka"
	"github.com/opencord/voltha-protos/v3/go/voltha"
)

// MockCoreProxy mocks the CoreProxy interface
type MockCoreProxy struct {
	// Values to be used in test can reside inside this structure
	// TODO store relevant info in this, use this info for negative and positive tests
	Devices map[string]*voltha.Device
}

// UpdateCoreReference mock updatesCoreReference
func (mcp *MockCoreProxy) UpdateCoreReference(deviceID string, coreReference string) {
	panic("implement me")
}

// DeleteCoreReference mock DeleteCoreReference function
func (mcp *MockCoreProxy) DeleteCoreReference(deviceID string) {
	panic("implement me")
}

// GetCoreTopic implements mock GetCoreTopic
func (mcp *MockCoreProxy) GetCoreTopic(deviceID string) kafka.Topic {
	panic("implement me")
}

// GetAdapterTopic implements mock GetAdapterTopic
func (mcp *MockCoreProxy) GetAdapterTopic(args ...string) kafka.Topic {
	panic("implement me")
}

// RegisterAdapter implements mock RegisterAdapter
func (mcp *MockCoreProxy) RegisterAdapter(ctx context.Context, adapter *voltha.Adapter,
	deviceTypes *voltha.DeviceTypes) error {
	if ctx == nil || adapter == nil || deviceTypes == nil {
		return errors.New("registerAdapter func parameters cannot be nil")
	}
	return nil
}

// DeviceUpdate implements mock DeviceUpdate
func (mcp *MockCoreProxy) DeviceUpdate(ctx context.Context, device *voltha.Device) error {
	if device.Id == "" {
		return errors.New("no Device")
	}
	return nil
}

// PortCreated implements mock PortCreated
func (mcp *MockCoreProxy) PortCreated(ctx context.Context, deviceID string, port *voltha.Port) error {
	if deviceID == "" {
		return errors.New("no deviceID")
	}
	if port.Type > 7 {
		return errors.New("invalid porttype")
	}
	return nil
}

// PortsStateUpdate implements mock PortsStateUpdate
func (mcp *MockCoreProxy) PortsStateUpdate(ctx context.Context, deviceID string, operStatus voltha.OperStatus_Types) error {
	if deviceID == "" {
		return errors.New("no Device")
	}
	return nil
}

// DeleteAllPorts implements mock DeleteAllPorts
func (mcp *MockCoreProxy) DeleteAllPorts(ctx context.Context, deviceID string) error {
	if deviceID == "" {
		return errors.New("no Device id")
	}
	return nil
}

// DeviceStateUpdate implements mock DeviceStateUpdate
func (mcp *MockCoreProxy) DeviceStateUpdate(ctx context.Context, deviceID string,
	connStatus voltha.ConnectStatus_Types, operStatus voltha.OperStatus_Types) error {
	if deviceID == "" {
		return errors.New("no Device id")
	}
	return nil
}

// ChildDeviceDetected implements mock ChildDeviceDetected
func (mcp *MockCoreProxy) ChildDeviceDetected(ctx context.Context, parentdeviceID string, parentPortNo int,
	childDeviceType string, channelID int, vendorID string, serialNumber string, onuID int64) (*voltha.Device, error) {
	if parentdeviceID == "" {
		return nil, errors.New("no deviceID")
	}
	return nil, nil
}

// ChildDevicesLost implements mock ChildDevicesLost.
func (mcp *MockCoreProxy) ChildDevicesLost(ctx context.Context, parentdeviceID string) error {
	//panic("implement me")
	if parentdeviceID == "" {
		return errors.New("no device id")
	}
	return nil
}

// ChildDevicesDetected implements mock ChildDevicesDetecte
func (mcp *MockCoreProxy) ChildDevicesDetected(ctx context.Context, parentdeviceID string) error {
	if parentdeviceID == "" {
		return errors.New("no device id")
	}
	return nil
}

// GetDevice implements mock GetDevice
func (mcp *MockCoreProxy) GetDevice(ctx context.Context, parentdeviceID string, deviceID string) (*voltha.Device, error) {
	if parentdeviceID == "" || deviceID == "" {
		return &voltha.Device{}, errors.New("no deviceID")
	}
	for k, v := range mcp.Devices {
		if k == "olt" {
			return v, nil
		}
	}
	return nil, errors.New("device detection failed")
}

// GetChildDevice implements mock GetChildDevice
func (mcp *MockCoreProxy) GetChildDevice(ctx context.Context, parentdeviceID string, kwargs map[string]interface{}) (*voltha.Device, error) {

	if parentdeviceID == "" {
		return nil, errors.New("device detection failed")
	}
	onuID := kwargs["onu_id"]
	var onuDevice *voltha.Device
	for _, val := range mcp.Devices {
		if val.GetId() == fmt.Sprintf("%v", onuID) {
			onuDevice = val
			break
		}
	}
	if onuDevice != nil {
		return onuDevice, nil
	}
	//return &voltha.Device{}, nil
	return nil, errors.New("device detection failed")
}

// GetChildDevices implements mock GetChildDevices
func (mcp *MockCoreProxy) GetChildDevices(ctx context.Context, parentdeviceID string) (*voltha.Devices, error) {
	if parentdeviceID == "" {
		return nil, errors.New("no deviceID")
	}
	onuDevices := make([]*voltha.Device, 0)

	for _, val := range mcp.Devices {
		if val != nil {
			onuDevices = append(onuDevices, val)
		}
	}

	deviceList := &voltha.Devices{Items: onuDevices}
	if len(deviceList.Items) > 0 {
		return deviceList, nil
	}
	return nil, errors.New("device detection failed")
}

// SendPacketIn  implements mock SendPacketIn
func (mcp *MockCoreProxy) SendPacketIn(ctx context.Context, deviceID string, port uint32, pktPayload []byte) error {
	if deviceID == "" {
		return errors.New("no Device ID")
	}
	return nil
}

// DeviceReasonUpdate  implements mock SendPacketIn
func (mcp *MockCoreProxy) DeviceReasonUpdate(ctx context.Context, deviceID string, reason string) error {
	if deviceID == "" {
		return errors.New("no Device ID")
	}
	return nil
}

// DevicePMConfigUpdate implements mock DevicePMConfigUpdate
func (mcp *MockCoreProxy) DevicePMConfigUpdate(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
	return nil
}

// PortStateUpdate implements mock PortStateUpdate
func (mcp *MockCoreProxy) PortStateUpdate(ctx context.Context, deviceID string, pType voltha.Port_PortType, portNo uint32,
	operStatus voltha.OperStatus_Types) error {
	return nil
}
