package wails

import (
	"context"

	"github.com/Eriyc/rules_wails/pkg/wails3kit/updates"
	"github.com/wailsapp/wails/v3/pkg/application"
)

type Options struct {
	App                *application.App
	Controller         *updates.Controller
	EventName          string
	AutoCheckOnStartup bool
	Emitter            func(string, any)
}

type Service struct {
	controller         *updates.Controller
	eventName          string
	autoCheckOnStartup bool
	emitter            func(string, any)
	stop               func()
	done               chan struct{}
}

func RegisterEvents(eventName string) {
	if eventName == "" {
		eventName = "updates:state"
	}
	application.RegisterEvent[updates.Snapshot](eventName)
}

func NewService(opts Options) *Service {
	eventName := opts.EventName
	if eventName == "" {
		eventName = "updates:state"
	}

	emitter := opts.Emitter
	if emitter == nil && opts.App != nil {
		emitter = func(name string, data any) {
			opts.App.Event.Emit(name, data)
		}
	}

	return &Service{
		controller:         opts.Controller,
		eventName:          eventName,
		autoCheckOnStartup: opts.AutoCheckOnStartup,
		emitter:            emitter,
		done:               make(chan struct{}),
	}
}

func (service *Service) ServiceStartup(_ context.Context, _ application.ServiceOptions) error {
	if service.controller == nil {
		return updates.ErrInvalidConfig
	}

	channel, stop := service.controller.Subscribe(4)
	service.stop = stop
	go func() {
		for {
			select {
			case <-service.done:
				return
			case snapshot := <-channel:
				if service.emitter != nil {
					service.emitter(service.eventName, snapshot)
				}
			}
		}
	}()

	if service.autoCheckOnStartup {
		go func() {
			_, _ = service.Check()
		}()
	}
	return nil
}

func (service *Service) ServiceShutdown() error {
	if service.stop != nil {
		service.stop()
	}
	select {
	case <-service.done:
	default:
		close(service.done)
	}
	return nil
}

func (service *Service) Snapshot() updates.Snapshot {
	return service.controller.Snapshot()
}

func (service *Service) Check() (updates.Snapshot, error) {
	return service.controller.Check(context.Background(), updates.CheckRequest{})
}

func (service *Service) Download() (updates.Snapshot, error) {
	return service.controller.Download(context.Background())
}

func (service *Service) ApplyAndRestart() error {
	return service.controller.ApplyAndRestart(context.Background())
}
