package scaler

import (
	"fmt"
	"os"
	"strconv"

	"git.stinnesbeck.com/go/jynx/backend/hetzner"
	"git.stinnesbeck.com/go/jynx/ci/woodpecker"
	"git.stinnesbeck.com/go/log"
)

func Start(w *woodpecker.Server) error {
	stats, err := w.GetStats()
	if err != nil {
		return err
	}

	// get the prefix for jynx managed servers
	prefix := os.Getenv("HETZNER_CLOUD_PREFIX")

	// set default prefix if none was provided
	if prefix == "" {
		prefix = "jynx"
	}

	// get a list of all servers from hetzner (from jynx)
	servers, err := hetzner.ListJynxServers(prefix)
	if err != nil {
		return err
	}

	newServers := stats.PendingJobs - len(servers) + stats.RunningJobs
	startingUp := len(servers) - stats.RunningJobs - stats.IdlingWorkers
	// check if the result is negative, if so set starting servers as 0
	// happens when servers are queued for deletion and api is polled in the
	// meantime
	if startingUp < 0 {
		startingUp = 0
	}

	log.PrintInfo(stats.RunningJobs, "running jobs,", stats.PendingJobs, "pending jobs,", stats.IdlingWorkers, "idling workers,", startingUp, "servers starting up")

	// check if there are servers to be removed
	if stats.PendingJobs == 0 && stats.RunningJobs == 0 {
		// we need to remove servers
		if err := hetzner.CheckServerDeletions(servers); err != nil {
			return err
		}
	}

	// check if we need to create new servers
	// if stats.PendingJobs < 1 || len(servers)-stats.RunningJobs >= stats.PendingJobs {
	if stats.PendingJobs < 1 || newServers < 1 {
		// if stats.PendingJobs == 0 || stats.IdlingWorkers+stats.RunningJobs >= stats.PendingJobs {
		// skip rest of this run
		return nil
	}

	if maxServersString := os.Getenv("HETZNER_SERVER_MAX"); maxServersString != "" {
		maxServers, err := strconv.Atoi(maxServersString)
		if err != nil {
			return err
		}
		// check if the maximum amount of servers is reached if one is provided
		if newServers+len(servers) > maxServers && maxServers != 0 {
			newServers = maxServers - len(servers)
		}
	}

	// if there are no servers to be created, exit here
	if newServers < 1 {
		return nil
	}

	// slice to hold servers to be created
	var ScaleUpServers []string

	// there are servers to be created
	// get the suffix for the starting server
	suffix, err := hetzner.GetNewSuffix(servers)
	for i := 0; i < newServers; i++ {
		if err != nil {
			return err
		}
		// assemble server name and add it to the list of servers to scale up
		serverName := fmt.Sprintf("%s-worker-%d", prefix, suffix)
		ScaleUpServers = append(ScaleUpServers, serverName)

		// add 1 to the suffix for the next server
		suffix++
	}

	log.PrintInfo("starting", newServers, "workers:", ScaleUpServers)

	// create servers on hetzner cloud
	if err := hetzner.CreateServers(ScaleUpServers); err != nil {
		return err
	}

	return nil
}