//go:build linux
// +build linux

package linux

import (
	"encoding/json"
	"github.com/godbus/dbus/v5"
	"github.com/wailsapp/wails/v2/pkg/options"
	"log"
	"os"
	"strings"
)

type dbusHandler func(string)

func (f dbusHandler) SendMessage(message string) *dbus.Error {
	f(message)
	return nil
}

func SetupSingleInstance(uniqueID string) {
	id := "wails_app_" + strings.ReplaceAll(strings.ReplaceAll(uniqueID, "-", "_"), ".", "_")

	dbusName := "org." + id + ".SingleInstance"
	dbusPath := "/org/" + id + "/SingleInstance"

	conn, err := dbus.ConnectSessionBus()
	// if we will reach any error during establishing connection or sending message we will just continue.
	// It should not be the case that such thing will happen actually, but just in case.
	if err != nil {
		return
	}

	f := dbusHandler(func(message string) {
		var secondInstanceData options.SecondInstanceData

		err := json.Unmarshal([]byte(message), &secondInstanceData)
		if err == nil {
			secondInstanceBuffer <- secondInstanceData
		}
	})

	err = conn.Export(f, dbus.ObjectPath(dbusPath), dbusName)
	if err != nil {
		return
	}

	reply, err := conn.RequestName(dbusName, dbus.NameFlagDoNotQueue)
	if err != nil {
		return
	}

	// if name already taken, try to send args to existing instance, if no success just launch new instance
	if reply == dbus.RequestNameReplyExists {
		data := options.SecondInstanceData{
			Args: os.Args[1:],
		}
		data.WorkingDirectory, err = os.Getwd()
		if err != nil {
			log.Printf("Failed to get working directory: %v", err)
			return
		}

		serialized, err := json.Marshal(data)
		if err != nil {
			log.Printf("Failed to marshal data: %v", err)
			return
		}

		err = conn.Object(dbusName, dbus.ObjectPath(dbusPath)).Call(dbusName+".SendMessage", 0, string(serialized)).Store()
		if err != nil {
			return
		}
		os.Exit(1)
	}
}
