//go:build windows
// +build windows

package utils

import (
	"fmt"
	teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
	"github.com/iwind/TeaGo/Tea"
	"golang.org/x/sys/windows"
	"golang.org/x/sys/windows/svc"
	"golang.org/x/sys/windows/svc/mgr"
	"os/exec"
)

// 安装服务
func (this *ServiceManager) Install(exePath string, args []string) error {
	m, err := mgr.Connect()
	if err != nil {
		return fmt.Errorf("connecting: %w please 'Run as administrator' again", err)
	}
	defer m.Disconnect()
	s, err := m.OpenService(this.Name)
	if err == nil {
		s.Close()
		return fmt.Errorf("service %s already exists", this.Name)
	}

	s, err = m.CreateService(this.Name, exePath, mgr.Config{
		DisplayName: this.Name,
		Description: this.Description,
		StartType:   windows.SERVICE_AUTO_START,
	}, args...)
	if err != nil {
		return fmt.Errorf("creating: %w", err)
	}
	defer s.Close()

	return nil
}

// 启动服务
func (this *ServiceManager) Start() error {
	m, err := mgr.Connect()
	if err != nil {
		return err
	}
	defer m.Disconnect()
	s, err := m.OpenService(this.Name)
	if err != nil {
		return fmt.Errorf("could not access service: %w", err)
	}
	defer s.Close()
	err = s.Start("service")
	if err != nil {
		return fmt.Errorf("could not start service: %w", err)
	}

	return nil
}

// 删除服务
func (this *ServiceManager) Uninstall() error {
	m, err := mgr.Connect()
	if err != nil {
		return fmt.Errorf("connecting: %w please 'Run as administrator' again", err)
	}
	defer m.Disconnect()
	s, err := m.OpenService(this.Name)
	if err != nil {
		return fmt.Errorf("open service: %w", err)
	}

	// shutdown service
	_, err = s.Control(svc.Stop)
	if err != nil {
		fmt.Printf("shutdown service: %s\n", err.Error())
	}

	defer s.Close()
	err = s.Delete()
	if err != nil {
		return fmt.Errorf("deleting: %w", err)
	}
	return nil
}

// 运行
func (this *ServiceManager) Run() {
	err := svc.Run(this.Name, this)
	if err != nil {
		this.LogError(err.Error())
	}
}

// 同服务管理器的交互
func (this *ServiceManager) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
	const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue

	changes <- svc.Status{
		State: svc.StartPending,
	}

	changes <- svc.Status{
		State:   svc.Running,
		Accepts: cmdsAccepted,
	}

	// start service
	this.Log("start")
	this.cmdStart()

loop:
	for {
		select {
		case c := <-r:
			switch c.Cmd {
			case svc.Interrogate:
				this.Log("cmd: Interrogate")
				changes <- c.CurrentStatus
			case svc.Stop, svc.Shutdown:
				this.Log("cmd: Stop|Shutdown")

				// stop service
				this.cmdStop()

				break loop
			case svc.Pause:
				this.Log("cmd: Pause")

				// stop service
				this.cmdStop()

				changes <- svc.Status{
					State:   svc.Paused,
					Accepts: cmdsAccepted,
				}
			case svc.Continue:
				this.Log("cmd: Continue")

				// start service
				this.cmdStart()

				changes <- svc.Status{
					State:   svc.Running,
					Accepts: cmdsAccepted,
				}
			default:
				this.LogError(fmt.Sprintf("unexpected control request #%d\r\n", c))
			}
		}
	}
	changes <- svc.Status{
		State: svc.StopPending,
	}
	return
}

// 启动Web服务
func (this *ServiceManager) cmdStart() {
	cmd := exec.Command(Tea.Root+Tea.DS+"bin"+Tea.DS+teaconst.SystemdServiceName+".exe", "start")
	err := cmd.Start()
	if err != nil {
		this.LogError(err.Error())
	}
}

// 停止Web服务
func (this *ServiceManager) cmdStop() {
	cmd := exec.Command(Tea.Root+Tea.DS+"bin"+Tea.DS+teaconst.SystemdServiceName+".exe", "stop")
	err := cmd.Start()
	if err != nil {
		this.LogError(err.Error())
	}
}
