package woodpecker

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"

	"git.stinnesbeck.com/go/log"
)

type Server struct {
	Host  string `json:"host"`
	Token string `json:"token"`
}

type Stats struct {
	PendingJobs   int `json:"woodpecker_pending_jobs"`
	RunningJobs   int `json:"woodpecker_running_jobs"`
	IdlingWorkers int `json:"woodpecker_worker_count"`
}

// NewServer returns a Server object for host
func NewServer(host string, token string) Server {
	switch {
	case strings.HasPrefix(host, "http://"), strings.HasPrefix(host, "https://"):
		return Server{
			Host:  host,
			Token: token,
		}
	default:
		log.PrintError("host needs to start with 'http://' or 'https://'")
		os.Exit(1)
		return Server{}
	}
}

func (s Server) GetStats() (*Stats, error) {
	// prepare request
	req, err := http.NewRequest(http.MethodGet, s.Host+"/metrics/", nil)
	if err != nil {
		return nil, err
	}

	// add authorization header
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", s.Token))

	c := http.DefaultClient
	response, err := c.Do(req)
	if err != nil {
		return nil, err
	}

	b, err := io.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	lines := strings.Split(string(b), "\n")

	r := regexp.MustCompile(`^((woodpecker_)(worker_count|pending_jobs|running_jobs)) (\d+)`)

	var stats Stats

	for i := range lines {
		// skip rest of loop if this line doesn't match regex
		if !r.MatchString(lines[i]) {
			continue
		}

		// line matches regex
		matches := r.FindStringSubmatch(lines[i])

		// assign stats to struct
		switch matches[3] {
		case "pending_jobs":
			stats.PendingJobs = parseStringToInt(matches[4])
		case "running_jobs":
			stats.RunningJobs = parseStringToInt(matches[4])
		case "worker_count":
			stats.IdlingWorkers = parseStringToInt(matches[4])
		}
	}

	return &stats, nil
}

// parseStringToInt parses a string and returns the resulting uint
func parseStringToInt(s string) int {
	num, err := strconv.Atoi(s)
	if err != nil {
		log.PrintError("can't parse string to uint,", err)
		os.Exit(1)
	}
	return num
}