/*
 * Copyright (c) 2025  The AdvantEDGE Authors
 *
 * 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 ance "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 onem2mmgr

import (
	"fmt"
	"testing"

	log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger"
)

const tmName = "meep-iot"
const tmNamespace = "sandboxtest"

func TestNewIotMgr(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())

	// Invalid Connector
	fmt.Println("Invalid IOT Asset Manager")
	tm, err := NewIotMgr("", tmNamespace)
	if err == nil || tm != nil {
		t.Fatalf("DB connection should have failed")
	}

	// Valid Connector
	fmt.Println("Create valid IOT Asset Manager")
	tm, err = NewIotMgr(tmName, tmNamespace)
	if err != nil || tm == nil {
		t.Fatalf("Failed to create IOT Asset Manager")
	}

	// Cleanup
	err = tm.DeleteIotMgr()
	if err != nil {
		t.Fatalf("Failed to cleanup IOT Asset Manager")
	}
}

func TestRegisterIotPlatformInfo(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())

	// Valid Connector
	fmt.Println("Create valid IOT Asset Manager")
	tm, err := NewIotMgr(tmName, tmNamespace)
	if err != nil || tm == nil {
		t.Fatalf("Failed to create IOT Asset Manager")
	}

	// Set a valid platform
	var adresses = []Addresses{}
	adresses = append(adresses, Addresses{
		Host: "172.29.10.56",
		Port: 1883,
	})
	var endpoint = EndPointInfo{
		Addresses: adresses,
	}
	var userTransportInfo = []MbTransportInfo{}
	userTransportInfo = append(userTransportInfo, MbTransportInfo{
		Id:          "d5673793-c55c-4969-b5bc-2121f84b9f8d",
		Name:        "MQTT",
		Description: "MQTT",
		Protocol:    "MQTT",
		Version:     "2",
		Endpoint:    &endpoint,
	})
	var adresses_1 = []Addresses{}
	adresses_1 = append(adresses_1, Addresses{
		Host: "172.29.10.20",
		Port: 31110,
	})
	var customServicesTransportInfo = []TransportInfo{}
	var endPointInfo_1 = EndPointInfo{
		Addresses: adresses_1,
	}
	customServicesTransportInfo = append(customServicesTransportInfo, TransportInfo{
		Id:          "2ddb713c-2b41-4ded-a7ad-a5a047c5df13",
		Name:        "/laboai-acme-ic-cse",
		Description: "ACME oneM2M CSE",
		Protocol:    "REST_HTTP",
		Version:     "4",
		Endpoint:    &endPointInfo_1,
	})
	var iotPlatformInfo = IotPlatformInfo{
		IotPlatformId:               "523f2df1-8927-429f-906c-56ba92d13762",
		UserTransportInfo:           userTransportInfo,
		CustomServicesTransportInfo: customServicesTransportInfo,
		Enabled:                     true,
	}
	fmt.Println("Create an IotPlatformInfo: ", iotPlatformInfo)
	err = tm.RegisterIotPlatformInfo(iotPlatformInfo)
	if err != nil {
		t.Fatalf("Failed to register new IoT platform")
	}

	// Cleanup
	err = tm.DeregisterIotPlatformInfo(iotPlatformInfo.IotPlatformId)
	if err != nil {
		t.Fatalf("Failed to register new IoT platform")
	}
	err = tm.DeleteIotMgr()
	if err != nil {
		t.Fatalf("Failed to cleanup IOT Asset Manager")
	}

	// t.Fatalf("DONE")
}

func TestOneM2mCreateAE(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())

	// Valid Connector
	fmt.Println("Create valid IOT Asset Manager")
	tm, err := NewIotMgr(tmName, tmNamespace)
	if err != nil || tm == nil {
		t.Fatalf("Failed to create IOT Asset Manager")
	}

	// Set a valid platform
	var adresses = []Addresses{}
	adresses = append(adresses, Addresses{
		Host: "172.29.10.56",
		Port: 1883,
	})
	var endpoint = EndPointInfo{
		Addresses: adresses,
	}
	var userTransportInfo = []MbTransportInfo{}
	userTransportInfo = append(userTransportInfo, MbTransportInfo{
		Id:          "d5673793-c55c-4969-b5bc-2121f84b9f8d",
		Name:        "MQTT",
		Description: "MQTT",
		Protocol:    "MQTT",
		Version:     "2",
		Endpoint:    &endpoint,
	})
	var adresses_1 = []Addresses{}
	adresses_1 = append(adresses_1, Addresses{
		Host: "172.29.10.20",
		Port: 31110,
	})
	var customServicesTransportInfo = []TransportInfo{}
	var endPointInfo_1 = EndPointInfo{
		Addresses: adresses_1,
	}
	customServicesTransportInfo = append(customServicesTransportInfo, TransportInfo{
		Id:          "2ddb713c-2b41-4ded-a7ad-a5a047c5df13",
		Name:        "/laboai-acme-ic-cse",
		Description: "ACME oneM2M CSE",
		Protocol:    "REST_HTTP",
		Version:     "4",
		Endpoint:    &endPointInfo_1,
	})
	var iotPlatformInfo = IotPlatformInfo{
		IotPlatformId:               "523f2df1-8927-429f-906c-56ba92d13762",
		UserTransportInfo:           userTransportInfo,
		CustomServicesTransportInfo: customServicesTransportInfo,
		Enabled:                     true,
	}
	// Create a new IotPlatformInfo
	fmt.Println("Create a new IotPlatformInfo")
	err = tm.RegisterIotPlatformInfo(iotPlatformInfo)
	if err != nil {
		t.Fatalf("Failed to register new IoT platform")
	}
	// Create an AE for this new IotPlatform
	fmt.Println("Create an AE for this new IotPlatform")
	requestedIotPlatformId := iotPlatformInfo.IotPlatformId
	var device = DeviceInfo{
		RequestedIotPlatformId: requestedIotPlatformId,
		DeviceId:               requestedIotPlatformId,
		Enabled:                true,
	}
	deviceResp, err := tm.oneM2M_create(device, requestedIotPlatformId, "AE")
	if err != nil {
		t.Fatalf("oneM2M_create failure")
	}
	fmt.Println("deviceResp: ", deviceResp)
	// Get the new IotPlatform entry
	fmt.Println("Get the new IotPlatform entry")
	deviceResp_1, err := tm.oneM2M_get(deviceResp, requestedIotPlatformId, "AE")
	if err != nil {
		t.Fatalf("oneM2M_get failure")
	}

	// Check deviceResp vs. deviceResp_1
	if !validate_device_info(deviceResp, deviceResp_1) {
		t.Fatalf("validate_device_info failure")
	}

	// Delete the new IotPlatform entry
	fmt.Println("Delete the new IotPlatform entry")
	err = tm.oneM2M_delete(deviceResp, requestedIotPlatformId, "AE")
	if err != nil {
		t.Fatalf("oneM2M_create failure")
	}

	// Cleanup
	err = tm.DeleteIotMgr()
	if err != nil {
		t.Fatalf("Failed to cleanup IOT Asset Manager")
	}

	// t.Fatalf("DONE")
}

func TestOneM2mCreateAEAndCNT(t *testing.T) {
	fmt.Println("--- ", t.Name())
	log.MeepTextLogInit(t.Name())

	// Valid Connector
	fmt.Println("Create valid IOT Asset Manager")
	tm, err := NewIotMgr(tmName, tmNamespace)
	if err != nil || tm == nil {
		t.Fatalf("Failed to create IOT Asset Manager")
	}

	// Register new IotPlatform and create AE entry
	fmt.Println("Register new IotPlatform and create AE entry")
	iotPlatformInfo, err := registerIotPltfAndCreateAE(tm)
	if err != nil {
		t.Fatalf("registerIotPltfAndCreateAE failure")
	}
	// Get the new IotPlatform and create AE entry
	fmt.Println("Get the new IotPlatform and create AE entry")
	deviceResp_1, err := tm.oneM2M_get(*iotPlatformInfo.DeviceInfo, iotPlatformInfo.IotPlatformId, "AE")
	if err != nil {
		t.Fatalf("oneM2M_get failure")
	}
	// Check deviceResp vs. deviceResp_1
	fmt.Println("Check deviceResp vs. deviceResp_1")
	if !validate_device_info(*iotPlatformInfo.DeviceInfo, deviceResp_1) {
		t.Fatalf("validate_device_info failure")
	}

	// Create a device for the IotPlatform
	var device = DeviceInfo{
		RequestedIotPlatformId: iotPlatformInfo.IotPlatformId,
		DeviceId:               "Device1",
		Enabled:                true,
		//DeviceMetadata:         [KeyValuePair{Key: "pi", Value: *iotPlatformInfo.DeviceInfo.DeviceMetadata[]}]
	}
	device, err = tm.oneM2M_create(device, iotPlatformInfo.IotPlatformId, "CNT")
	if err != nil {
		t.Fatalf("oneM2M_create failed to create a device")
	}
	fmt.Println("device: ", device)

	// Delete the new IotPlatform entry
	fmt.Println("Delete the new IotPlatform entry")
	err = tm.oneM2M_delete(*iotPlatformInfo.DeviceInfo, iotPlatformInfo.IotPlatformId, "AE")
	if err != nil {
		t.Fatalf("oneM2M_create failure")
	}

	// Cleanup
	err = tm.DeleteIotMgr()
	if err != nil {
		t.Fatalf("Failed to cleanup IOT Asset Manager")
	}

	// t.Fatalf("DONE")
}

func registerIotPltfAndCreateAE(tm *IotMgr) (iotPlatformInfo IotPlatformInfo, err error) {

	// Set a valid platform
	var adresses = []Addresses{}
	adresses = append(adresses, Addresses{
		Host: "172.29.10.56",
		Port: 1883,
	})
	var endpoint = EndPointInfo{
		Addresses: adresses,
	}
	var userTransportInfo = []MbTransportInfo{}
	userTransportInfo = append(userTransportInfo, MbTransportInfo{
		Id:          "d5673793-c55c-4969-b5bc-2121f84b9f8d",
		Name:        "MQTT",
		Description: "MQTT",
		Protocol:    "MQTT",
		Version:     "2",
		Endpoint:    &endpoint,
	})
	var adresses_1 = []Addresses{}
	adresses_1 = append(adresses_1, Addresses{
		Host: "172.29.10.20",
		Port: 31110,
	})
	var customServicesTransportInfo = []TransportInfo{}
	var endPointInfo_1 = EndPointInfo{
		Addresses: adresses_1,
	}
	customServicesTransportInfo = append(customServicesTransportInfo, TransportInfo{
		Id:          "2ddb713c-2b41-4ded-a7ad-a5a047c5df13",
		Name:        "/laboai-acme-ic-cse",
		Description: "ACME oneM2M CSE",
		Protocol:    "REST_HTTP",
		Version:     "4",
		Endpoint:    &endPointInfo_1,
	})
	iotPlatformInfo = IotPlatformInfo{
		IotPlatformId:               "523f2df1-8927-429f-906c-56ba92d13762",
		UserTransportInfo:           userTransportInfo,
		CustomServicesTransportInfo: customServicesTransportInfo,
		Enabled:                     true,
	}
	err = tm.RegisterIotPlatformInfo(iotPlatformInfo)
	if err != nil {
		return iotPlatformInfo, err
	}

	// OneM2M create MEC pltf as an AE
	requestedIotPlatformId := iotPlatformInfo.IotPlatformId
	var device = DeviceInfo{
		RequestedIotPlatformId: requestedIotPlatformId,
		DeviceId:               requestedIotPlatformId,
		Enabled:                true,
	}
	d, err := tm.oneM2M_create(device, requestedIotPlatformId, "AE")
	if err != nil {
		return iotPlatformInfo, err
	}
	iotPlatformInfo.DeviceInfo = new(DeviceInfo)
	*iotPlatformInfo.DeviceInfo = d
	fmt.Println("iotPlatformInfo.DeviceInfo: ", *iotPlatformInfo.DeviceInfo)

	return iotPlatformInfo, nil
}

func validate_device_info(expected_device DeviceInfo, received_deviceResp DeviceInfo) bool {
	if expected_device.DeviceId != received_deviceResp.DeviceId {
		fmt.Println(" received_deviceResp.DeviceId != DeviceId")
		return false
	}
	if expected_device.Enabled != received_deviceResp.Enabled {
		fmt.Println(" received_deviceResp.Enabled != Enabled")
		return false
	}
	// TODO To be continued

	return true
}
