// "build integration

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

import (
	"context"
	"fmt"
	"os/exec"
	"strings"
	"time"

	"github.com/golang/protobuf/ptypes/empty"
	"github.com/google/uuid"
	com "github.com/opencord/voltha-lib-go/v3/pkg/adapters/common"
	"github.com/opencord/voltha-lib-go/v3/pkg/log"
	"github.com/opencord/voltha-protos/v3/go/common"
	ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
	"github.com/opencord/voltha-protos/v3/go/voltha"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
)

// constant represents voltha serial number
const (
	VolthaSerialNumberKey = "voltha_serial_number"
)

func startKafka(composePath string) error {
	fmt.Println("Starting Kafka and Etcd ...")
	command := "docker-compose"
	fileName := fmt.Sprintf("%s/docker-compose-zk-kafka-test.yml", composePath)
	cmd := exec.Command(command, "-f", fileName, "up", "-d")
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func startEtcd(composePath string) error {
	fmt.Println("Starting Etcd ...")
	command := "docker-compose"
	fileName := fmt.Sprintf("%s/docker-compose-etcd.yml", composePath)
	cmd := exec.Command(command, "-f", fileName, "up", "-d")
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func stopKafka(composePath string) error {
	fmt.Println("Stopping Kafka and Etcd ...")
	command := "docker-compose"
	fileName := fmt.Sprintf("%s/docker-compose-zk-kafka-test.yml", composePath)
	cmd := exec.Command(command, "-f", fileName, "down")
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func stopEtcd(composePath string) error {
	fmt.Println("Stopping Etcd ...")
	command := "docker-compose"
	fileName := fmt.Sprintf("%s/docker-compose-etcd.yml", composePath)
	cmd := exec.Command(command, "-f", fileName, "down")
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func startCore(composePath string) error {
	fmt.Println("Starting voltha core ...")
	command := "docker-compose"
	fileName := fmt.Sprintf("%s/rw_core.yml", composePath)
	cmd := exec.Command(command, "-f", fileName, "up", "-d")
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func stopCore(composePath string) error {
	fmt.Println("Stopping voltha core ...")
	command := "docker-compose"
	fileName := fmt.Sprintf("%s/rw_core.yml", composePath)
	cmd := exec.Command(command, "-f", fileName, "down")
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func startSimulatedOLTAndONUAdapters(composePath string) error {
	fmt.Println("Starting simulated OLT and ONU adapters ...")
	command := "docker-compose"
	fileName := fmt.Sprintf("%s/adapters-simulated.yml", composePath)
	cmd := exec.Command(command, "-f", fileName, "up", "-d")
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func stopSimulatedOLTAndONUAdapters(composePath string) error {
	fmt.Println("Stopping simulated OLT and ONU adapters ...")
	command := "docker-compose"
	fileName := fmt.Sprintf("%s/adapters-simulated.yml", composePath)
	cmd := exec.Command(command, "-f", fileName, "down")
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

// ListLogicalDevices lists all logical devices managed by the Voltha cluster
func ListLogicalDevices(stub voltha.VolthaServiceClient) (*voltha.LogicalDevices, error) {
	ui := uuid.New()
	ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(VolthaSerialNumberKey, ui.String()))
	return stub.ListLogicalDevices(ctx, &empty.Empty{})
}

func sendCreateDeviceRequest(ctx context.Context, stub voltha.VolthaServiceClient, device *voltha.Device, ch chan interface{}) {
	if response, err := stub.CreateDevice(ctx, device); err != nil {
		ch <- err
	} else {
		ch <- response
	}
}

func sendListAdapters(ctx context.Context, stub voltha.VolthaServiceClient, ch chan interface{}) {
	if response, err := stub.ListAdapters(ctx, &empty.Empty{}); err != nil {
		ch <- err
	} else {
		ch <- response
	}
}

func sendEnableDeviceRequest(ctx context.Context, stub voltha.VolthaServiceClient, deviceID string, ch chan interface{}) {
	if response, err := stub.EnableDevice(ctx, &common.ID{Id: deviceID}); err != nil {
		ch <- err
	} else {
		ch <- response
	}
}

func getDevices(ctx context.Context, stub voltha.VolthaServiceClient) (*voltha.Devices, error) {
	return stub.ListDevices(ctx, &empty.Empty{})
}

func getLogicalDevices(ctx context.Context, stub voltha.VolthaServiceClient) (*voltha.LogicalDevices, error) {
	return stub.ListLogicalDevices(ctx, &empty.Empty{})
}

// IsFlowPresent returns true if flow is present
func IsFlowPresent(lookingFor *voltha.OfpFlowStats, flows []*voltha.OfpFlowStats) bool {
	for _, f := range flows {
		if f.String() == lookingFor.String() {
			return true
		}
	}
	return false
}

// ListDevices lists all physical devices controlled by the Voltha cluster
func ListDevices(stub voltha.VolthaServiceClient) (*voltha.Devices, error) {
	ui := uuid.New()
	ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(VolthaSerialNumberKey, ui.String()))
	return getDevices(ctx, stub)
}

func sendFlow(ctx context.Context, stub voltha.VolthaServiceClient, flow *ofp.FlowTableUpdate, ch chan interface{}) {
	if response, err := stub.UpdateLogicalDeviceFlowTable(ctx, flow); err != nil {
		ch <- err
	} else {
		ch <- response
	}
}

// SetupGrpcConnectionToCore sets up client connection to an RPC server.
func SetupGrpcConnectionToCore(grpcHostIP string, grpcPort int) (voltha.VolthaServiceClient, error) {
	grpcHost := fmt.Sprintf("%s:%d", grpcHostIP, grpcPort)
	fmt.Println("Connecting to voltha using:", grpcHost)
	conn, err := grpc.Dial(grpcHost, grpc.WithInsecure())
	if err != nil {
		return nil, err
	}
	return voltha.NewVolthaServiceClient(conn), nil
}

// VerifyLogicalDevices verifies all logical devices managed by the Voltha cluster
func VerifyLogicalDevices(stub voltha.VolthaServiceClient, parentDevice *voltha.Device, numONUsPerOLT int) (*voltha.LogicalDevices, error) {
	ui := uuid.New()
	ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(VolthaSerialNumberKey, ui.String()))
	retrievedLogicalDevices, err := getLogicalDevices(ctx, stub)
	if err != nil {
		return nil, err
	}
	if len(retrievedLogicalDevices.Items) != 1 {
		return nil, status.Errorf(codes.Internal, "Logical device number incorrect. Expected:{%d}, Created:{%d}", 1, len(retrievedLogicalDevices.Items))
	}

	// Verify that each device has two ports
	for _, ld := range retrievedLogicalDevices.Items {
		if ld.Id == "" ||
			ld.DatapathId == uint64(0) ||
			ld.Desc.HwDesc != "simulated_pon" ||
			ld.Desc.SwDesc != "simulated_pon" ||
			ld.RootDeviceId == "" ||
			ld.Desc.SerialNum == "" ||
			ld.SwitchFeatures.NBuffers != uint32(256) ||
			ld.SwitchFeatures.NTables != uint32(2) ||
			ld.SwitchFeatures.Capabilities != uint32(15) ||
			len(ld.Ports) != 1+numONUsPerOLT ||
			ld.RootDeviceId != parentDevice.Id {
			return nil, status.Errorf(codes.Internal, "incorrect logical device status:{%v}", ld)
		}
		for _, p := range ld.Ports {
			if p.DevicePortNo != p.OfpPort.PortNo ||
				p.OfpPort.State != uint32(4) {
				return nil, status.Errorf(codes.Internal, "incorrect logical ports status:{%v}", p)
			}
			if strings.HasPrefix(p.Id, "nni") {
				if !p.RootPort || fmt.Sprintf("nni-%d", p.DevicePortNo) != p.Id {
					return nil, status.Errorf(codes.Internal, "incorrect nni port status:{%v}", p)
				}
			} else {
				if p.RootPort || fmt.Sprintf("uni-%d", p.DevicePortNo) != p.Id {
					return nil, status.Errorf(codes.Internal, "incorrect uni port status:{%v}", p)
				}
			}
		}
	}
	return retrievedLogicalDevices, nil
}

// VerifyDevices verifies all physical devices controlled by the Voltha cluster
func VerifyDevices(stub voltha.VolthaServiceClient, numONUsPerOLT int) error {
	ui := uuid.New()
	ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(VolthaSerialNumberKey, ui.String()))
	retrievedDevices, err := getDevices(ctx, stub)
	if err != nil {
		return err
	}
	if len(retrievedDevices.Items) != 1+numONUsPerOLT {
		return status.Errorf(codes.Internal, "Device number incorrect. Expected:{%d}, Created:{%d}", 1, len(retrievedDevices.Items))
	}
	// Verify that each device has two ports
	for _, d := range retrievedDevices.Items {
		if d.AdminState != voltha.AdminState_ENABLED ||
			d.ConnectStatus != voltha.ConnectStatus_REACHABLE ||
			d.OperStatus != voltha.OperStatus_ACTIVE ||
			d.Type != d.Adapter ||
			d.Id == "" ||
			d.MacAddress == "" ||
			d.SerialNumber == "" {
			return status.Errorf(codes.Internal, "incorrect device state - %s", d.Id)
		}

		if d.Type == "simulated_olt" && (!d.Root || d.ProxyAddress != nil) {
			return status.Errorf(codes.Internal, "invalid olt status:{%v}", d)
		} else if d.Type == "simulated_onu" && (d.Root ||
			d.Vlan == uint32(0) ||
			d.ParentId == "" ||
			d.ProxyAddress.DeviceId == "" ||
			d.ProxyAddress.DeviceType != "simulated_olt") {
			return status.Errorf(codes.Internal, "invalid onu status:{%s}", d.Id)
		}

		if len(d.Ports) != 2 {
			return status.Errorf(codes.Internal, "invalid number of ports:{%s, %v}", d.Id, d.Ports)
		}

		for _, p := range d.Ports {
			if p.AdminState != voltha.AdminState_ENABLED ||
				p.OperStatus != voltha.OperStatus_ACTIVE {
				return status.Errorf(codes.Internal, "invalid port state:{%s, %v}", d.Id, p)
			}

			if p.Type == voltha.Port_ETHERNET_NNI || p.Type == voltha.Port_ETHERNET_UNI {
				if len(p.Peers) != 0 {
					return status.Errorf(codes.Internal, "invalid length of peers:{%s, %d}", d.Id, p.Type)
				}
			} else if p.Type == voltha.Port_PON_OLT {
				if len(p.Peers) != numONUsPerOLT ||
					p.PortNo != uint32(1) {
					return status.Errorf(codes.Internal, "invalid length of peers for PON OLT port:{%s, %v}", d.Id, p)
				}
			} else if p.Type == voltha.Port_PON_ONU {
				if len(p.Peers) != 1 ||
					p.PortNo != uint32(1) {
					return status.Errorf(codes.Internal, "invalid length of peers for PON ONU port:{%s, %v}", d.Id, p)
				}
			}
		}
	}
	return nil
}

func areAdaptersPresent(requiredAdapterNames []string, retrievedAdapters *voltha.Adapters) bool {
	if len(requiredAdapterNames) == 0 {
		return true
	}
	for _, nAName := range requiredAdapterNames {
		found := false
		for _, rA := range retrievedAdapters.Items {
			if nAName == rA.Id {
				found = true
				break
			}
		}
		if !found {
			return false
		}
	}
	return true
}

// WaitForAdapterRegistration waits on channel for response of list adapters
func WaitForAdapterRegistration(stub voltha.VolthaServiceClient, requiredAdapterNames []string, timeout int) (*voltha.Adapters, error) {
	fmt.Println("Waiting for adapter registration ...")
	ui := uuid.New()
	ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(VolthaSerialNumberKey, ui.String()))
	ch := make(chan interface{})
	defer close(ch)
	for {
		go sendListAdapters(ctx, stub, ch)
		select {
		case res, ok := <-ch:
			if !ok {
				return nil, status.Error(codes.Aborted, "channel closed")
			} else if er, ok := res.(error); ok {
				return nil, er
			} else if a, ok := res.(*voltha.Adapters); ok {
				if areAdaptersPresent(requiredAdapterNames, a) {
					fmt.Println("All adapters registered:", a.Items)
					return a, nil
				}
			}
		case <-time.After(time.Duration(timeout) * time.Second):
			return nil, status.Error(codes.Aborted, "timeout while waiting for adapter registration")
		}
		time.Sleep(1 * time.Second)
	}
}

// PreProvisionDevice pre-provisions a new physical device
func PreProvisionDevice(stub voltha.VolthaServiceClient) (*voltha.Device, error) {
	ui := uuid.New()
	ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(VolthaSerialNumberKey, ui.String()))
	randomMacAddress := strings.ToUpper(com.GetRandomMacAddress())
	device := &voltha.Device{Type: "simulated_olt", MacAddress: randomMacAddress}
	ch := make(chan interface{})
	defer close(ch)
	go sendCreateDeviceRequest(ctx, stub, device, ch)
	res, ok := <-ch
	if !ok {
		return nil, status.Error(codes.Aborted, "channel closed")
	} else if er, ok := res.(error); ok {
		return nil, er
	} else if d, ok := res.(*voltha.Device); ok {
		return d, nil
	}
	return nil, status.Errorf(codes.Unknown, "cannot provision device:{%v}", device)
}

// EnableDevice - if the device was in pre-provisioned state then it
// will transition to ENABLED state.  If it was is DISABLED state then it
// will transition to ENABLED state as well.
func EnableDevice(stub voltha.VolthaServiceClient, device *voltha.Device, numONUs int) error {
	if device.AdminState == voltha.AdminState_PREPROVISIONED {
		ui := uuid.New()
		ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(VolthaSerialNumberKey, ui.String()))
		ch := make(chan interface{})
		defer close(ch)
		go sendEnableDeviceRequest(ctx, stub, device.Id, ch)
		res, ok := <-ch
		if !ok {
			return status.Error(codes.Aborted, "channel closed")
		} else if er, ok := res.(error); ok {
			return er
		} else if _, ok := res.(*empty.Empty); ok {
			return nil
		}
	}
	return status.Errorf(codes.Unknown, "cannot enable device:{%s}", device.Id)
}

// UpdateFlow updates flow table for logical device
func UpdateFlow(stub voltha.VolthaServiceClient, flow *ofp.FlowTableUpdate) error {
	ui := uuid.New()
	ctx := metadata.NewOutgoingContext(context.Background(), metadata.Pairs(VolthaSerialNumberKey, ui.String()))
	ch := make(chan interface{})
	defer close(ch)
	go sendFlow(ctx, stub, flow, ch)
	res, ok := <-ch
	if !ok {
		return status.Error(codes.Aborted, "channel closed")
	} else if er, ok := res.(error); ok {
		return er
	} else if _, ok := res.(*empty.Empty); ok {
		return nil
	}
	return status.Errorf(codes.Unknown, "cannot add flow:{%v}", flow)
}

// StartSimulatedEnv starts kafka, etcd, olt, onu adapters, core
func StartSimulatedEnv(composePath string) error {
	fmt.Println("Starting simulated environment ...")
	// Start kafka and Etcd
	if err := startKafka(composePath); err != nil {
		return err
	}
	if err := startEtcd(composePath); err != nil {
		return err
	}
	time.Sleep(5 * time.Second)

	//Start the simulated adapters
	if err := startSimulatedOLTAndONUAdapters(composePath); err != nil {
		return err
	}

	//Start the core
	if err := startCore(composePath); err != nil {
		return err
	}

	time.Sleep(10 * time.Second)

	fmt.Println("Simulated environment started.")
	return nil
}

// StopSimulatedEnv stops kafka, etcd, olt, onu adapters, core
func StopSimulatedEnv(ctx context.Context, composePath string) error {
	err := stopSimulatedOLTAndONUAdapters(composePath)
	if err != nil {
		logger.Errorw(ctx, "unable-to-stop-simulated-olt-onu-adapters", log.Fields{"error": err})
	}
	err = stopCore(composePath)
	if err != nil {
		logger.Errorw(ctx, "unable-to-stop-core", log.Fields{"error": err})
	}
	err = stopKafka(composePath)
	if err != nil {
		logger.Errorw(ctx, "unable-to-stop-kafka", log.Fields{"error": err})
	}
	err = stopEtcd(composePath)
	if err != nil {
		logger.Errorw(ctx, "unable-to-stop-etcd", log.Fields{"error": err})
	}
	return nil
}
