package service

import (
	"context"
	"errors"
	"log"
	"time"

	"aot-printer-agent/internal/config"
)

type Loop interface {
	Run(ctx context.Context) error
	RunOnce(ctx context.Context) error
}

type App struct {
	Config    config.Config
	Logger    *log.Logger
	Heartbeat Loop
	Claimer   Loop
}

func (a App) Run(ctx context.Context) error {
	a.Logger.Printf("service starting agent_uuid=%s agent_name=%q", a.Config.AgentUUID, a.Config.AgentName)

	errCh := make(chan error, 2)

	go func() { errCh <- a.Heartbeat.Run(ctx) }()
	go func() { errCh <- a.Claimer.Run(ctx) }()

	select {
	case <-ctx.Done():
		a.Logger.Print("service stopping")
		time.Sleep(200 * time.Millisecond)
		return nil
	case err := <-errCh:
		if errors.Is(err, config.ErrConfigUpdated) {
			a.Logger.Print("service stopping for config reload")
			return nil
		}
		return err
	}
}

func (a App) RunOnce(ctx context.Context) error {
	a.Logger.Print("run-once starting")
	if err := a.Heartbeat.RunOnce(ctx); err != nil {
		if errors.Is(err, config.ErrConfigUpdated) {
			a.Logger.Print("run-once stopped after config update")
			return nil
		}
		return err
	}
	if err := a.Claimer.RunOnce(ctx); err != nil {
		return err
	}
	a.Logger.Print("run-once complete")
	return nil
}
