package main

import (
	"log"
	"os"
	"sync"
	"time"
)

type Logger interface {
	Printf(format string, v ...any)
	Println(v ...any)
}

type Service struct {
	Name string
	Logger
	stop     chan struct{}
	complete chan struct{}
	mu       sync.Mutex
}

func NewService(n string, l Logger) *Service {
	stop := make(chan struct{})
	complete := make(chan struct{})
	return &Service{
		Name:     n,
		Logger:   l,
		stop:     stop,
		complete: complete,
		mu:       sync.Mutex{},
	}
}

func (s *Service) Init() {
	s.Logger.Printf("initializing : %s\n", s.Name)
}

func (s *Service) Run() {
	go func() {
		for {
			select {
			case <-s.stop:
				s.Logger.Println("ending process")
				s.mu.Lock()
				defer s.mu.Unlock()
				close(s.complete)
				return
			default:
				time.Sleep(time.Second)
				s.Logger.Println("doing some work...")
			}
		}
	}()
}

func (s *Service) Stop() {
	s.mu.Lock()
	close(s.stop)
	s.mu.Unlock()
	s.Logger.Printf("shutting down: %s\n", s.Name)
	<-s.complete
	s.Logger.Printf("shutdown successful")
}

func main() {
	l := log.New(os.Stdout, "[service] ", log.Lshortfile)
	s := NewService("example", l)
	s.Init()
	s.Run()
	// let the program fun for a while
	time.Sleep(10 * time.Second)
	s.Stop()
}
