package interfaces

import (
	"netease_control_center/globals"
	"netease_control_center/interfaces/log"
	"netease_control_center/utils/godbus/dbus"
	"os"
	"runtime/debug"
	"time"
)

const (
	NETEASE_DBUS_BUS_NAME = "netease.ihw.controller"

	NETEASE_DBUS_INTERFACE_COMMONNAME = "netease.ihw.SmartAudio"

	NETEASE_DBUS_SIGNAL_NAME = "Notify"
	NETEASE_DBUS_METHOD_NAME = "API"
)

var (
	Conn   *dbus.Conn      = nil
	busobj *dbus.BusObject = nil
)

func Init() {
	log.Println(log.DebugLog, "Init dbus interface")
	Conn, _ = dbus.SessionBus()

	replay, err := Conn.RequestName(NETEASE_DBUS_BUS_NAME, dbus.NameFlagDoNotQueue)

	if err != nil {
		log.Println(log.ErrorLog, "dbus request error ", err)
		panic(err)
	}

	if replay != dbus.RequestNameReplyPrimaryOwner {
		log.Println(log.ErrorLog, "Name has already been taken, exit!s")
		log.Println(log.ErrorLog, replay)
		os.Exit(1)
	}

	//Signal
	//controller chan
	Conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
		`type='signal',interface='`+NETEASE_DBUS_INTERFACE_COMMONNAME+`'`)

	//Register modules
	for modid, mod := range globals.Modules {
		log.Printf(log.DebugLog, "Init dbus interface,%d:%+v\n", modid, mod)
		if mod.NeedSeqHandle == true {
			log.Println(log.ErrorLog, modid, "begin registe mod")
			Conn.AddSeqModId(modid)
			Conn.RegisteSeqSigHandleFunc(mod.SeqSigHandFunc)
			log.Println(log.DebugLog, modid, "get seq mod ids:", Conn.GetSeqModId())
		} else {
			log.Println(log.ErrorLog, modid, mod.Path, "Do not need seq handle!")
		}

		if mod.Init == false {
			continue
		}

		if mod.SignalChan != nil {
			Conn.Signal(mod.SignalChan)
		}

		Conn.ExportMethodTable(*mod.MethodMap, dbus.ObjectPath(mod.Path), NETEASE_DBUS_INTERFACE_COMMONNAME)
	}
}

func SendCommand(fromId uint32, destId uint32, cmdId uint32, data *[]byte) {
	defer func() {
		if err := recover(); err != nil {
			debug.PrintStack()
			log.Println(log.ErrorLog, "Send cmd err:", err)
		}
	}()
	var msk uint32
	if destId == 0 {
		msk = 0xffffffff
	} else {
		msk = 1 << destId
	}

	var tmp string
	if data != nil {
		tmp = string(*data)
	} else {
		tmp = ""
	}
	Conn.Object(globals.Modules[destId].Aliase, dbus.ObjectPath(globals.Modules[destId].Path)).
		Go(NETEASE_DBUS_INTERFACE_COMMONNAME+"."+NETEASE_DBUS_METHOD_NAME, dbus.FlagNoReplyExpected, nil,
			fromId,
			uint32(msk),
			cmdId,
			uint32(len(tmp)),
			tmp)
	log.Printf(log.DebugLog, "cmdId:0x%x len:%d %s\n", cmdId, len(tmp), string(tmp))
}

func JustSendBusCmd(fromId uint32, destId uint32, cmdId uint32) {
	var msk uint32
	if destId == 0 {
		msk = 0xffffffff
	} else {
		msk = 1 << destId
	}

	var tmp string = ""

	Conn.Object(globals.Modules[destId].Aliase, dbus.ObjectPath(globals.Modules[destId].Path)).
		Go(NETEASE_DBUS_INTERFACE_COMMONNAME+"."+NETEASE_DBUS_METHOD_NAME, dbus.FlagNoReplyExpected, nil,
			fromId,
			uint32(msk),
			cmdId,
			uint32(len(tmp)),
			tmp)

	log.Printf(log.DebugLog, "sendCmdId: 0x%x\n", cmdId)
}

func BroadSignalAll(srcId uint32, buscmd uint32, data string) error {
	return BroadSignal(srcId, uint32(0xffffffff), buscmd, NETEASE_DBUS_INTERFACE_COMMONNAME, NETEASE_DBUS_SIGNAL_NAME, data)
}

func BroadSignal(srcId uint32, toMask uint32, buscmd uint32, interfaceName string, memberName string, data string) error {
	return Conn.Emit(dbus.ObjectPath(globals.Modules[srcId].Path), NETEASE_DBUS_INTERFACE_COMMONNAME+"."+memberName, srcId, toMask, buscmd, data)
}

func TestDbusSignal() {
	for {
		i := 0
		log.Println(log.DebugLog, "Do test", i)
		i++
		//tmp := []byte("hahah!!!!")
		//BroadSignalAll(globals.MODULE_CONTROLLER, 123, "this is data, buscmd: 123")
		//SendCommand(globals.MODULE_CONTROLLER, globals.MODULE_VOICEENGINE, 2048, &tmp)

		time.Sleep(1000 * time.Millisecond)
	}
}
