package infinitime

import (
	"github.com/godbus/dbus/v5"
	bt "github.com/muka/go-bluetooth/api"
	"github.com/muka/go-bluetooth/bluez/profile/adapter"
	"github.com/muka/go-bluetooth/bluez/profile/agent"
	"github.com/muka/go-bluetooth/hw/linux/btmgmt"
)

var defaultAdapter *adapter.Adapter1
var itdAgent *Agent

func Init() {
	conn, err := dbus.SystemBus()
	if err != nil {
		panic(err)
	}

	ag := &Agent{}
	err = agent.ExposeAgent(conn, ag, agent.CapKeyboardDisplay, true)
	if err != nil {
		panic(err)
	}

	// Get bluez default adapter
	da, err := bt.GetDefaultAdapter()
	if err != nil {
		panic(err)
	}

	daMgmt := btmgmt.NewBtMgmt(bt.GetDefaultAdapterID())
	daMgmt.SetPowered(true)

	defaultAdapter = da
	itdAgent = ag
}

func Exit() error {
	if defaultAdapter != nil {
		defaultAdapter.Close()
	}
	agent.RemoveAgent(itdAgent)
	return bt.Exit()
}

var errAuthFailed = dbus.NewError("org.bluez.Error.AuthenticationFailed", nil)

// Agent implements the agent.Agent1Client interface.
// It only requires RequestPasskey as that is all InfiniTime
// will use.
type Agent struct {
	ReqPasskey func() (uint32, error)
}

// Release returns nil
func (*Agent) Release() *dbus.Error {
	return nil
}

// RequestPinCode returns an empty string and nil
func (*Agent) RequestPinCode(device dbus.ObjectPath) (pincode string, err *dbus.Error) {
	return "", nil
}

// DisplayPinCode returns nil
func (*Agent) DisplayPinCode(device dbus.ObjectPath, pincode string) *dbus.Error {
	return nil
}

// RequestPasskey runs Agent.ReqPasskey and returns the result
func (a *Agent) RequestPasskey(device dbus.ObjectPath) (uint32, *dbus.Error) {
	if a.ReqPasskey == nil {
		return 0, errAuthFailed
	}
	log.Debug().Msg("Passkey requested, calling onReqPasskey callback")
	passkey, err := a.ReqPasskey()
	if err != nil {
		return 0, errAuthFailed
	}
	return passkey, nil
}

// DisplayPasskey returns nil
func (*Agent) DisplayPasskey(device dbus.ObjectPath, passkey uint32, entered uint16) *dbus.Error {
	return nil
}

// RequestConfirmation returns nil
func (*Agent) RequestConfirmation(device dbus.ObjectPath, passkey uint32) *dbus.Error {
	return nil
}

// RequestAuthorization returns nil
func (*Agent) RequestAuthorization(device dbus.ObjectPath) *dbus.Error {
	return nil
}

// AuthorizeService returns nil
func (*Agent) AuthorizeService(device dbus.ObjectPath, uuid string) *dbus.Error {
	return nil
}

// Cancel returns nil
func (*Agent) Cancel() *dbus.Error {
	return nil
}

// Path returns "/dev/arsenm/infinitime/Agent"
func (*Agent) Path() dbus.ObjectPath {
	return "/dev/arsenm/infinitime/Agent"
}

// Interface returns "org.bluez.Agent1"
func (*Agent) Interface() string {
	return "org.bluez.Agent1"
}