package main

import (
	"bytes"
	"os/exec"
	"syscall"
	"time"

	"github.com/rs/zerolog/log"
)

var currentConfig config

func main() {
	var err error
	currentConfig, err = ReadFromFile("config.yml")
	if err != nil {
		log.Fatal().Err(err).Msg("Cant read config file")
	}
	log.Debug().Interface("config", currentConfig).Msg("config")

	if len(currentConfig.Jobs) == 0 {
		log.Warn().Msg("config dont include any jobs")
	}
	cronTicker, configTicker := createTickers(realTimeProvider{})

	// Hauptloop mit select
	for {
		select {
		case t := <-cronTicker:
			execucteJobs(t, currentConfig)
		case <-configTicker:
			log.Debug().Msg("Reload Config")
			currentConfig, err = ReadFromFile("config.yml")
			if err != nil {
				log.Error().Err(err).Msg("cant read config")
			}
		}
	}
}

func execucteJobs(t time.Time, c config) {
	for _, job := range c.Jobs {
		execute, err := job.MatchCurrentTime(t)
		log.Debug().Bool("execution", execute).Time("t", t).Msg("check cron execution")
		if err != nil {
			log.Error().Err(err).Msg("cant pars time for job")
		}
		if !execute {
			continue
		}

		go executeJob(t, job, c)
	}
}

func executeJob(t time.Time, job jobconfig, c config) {
	result, err := executeCommand(job)
	log.Info().Str("name", job.Name).Str("command", job.Command).Time("execute-for", t).Int("execCode", result.execCode).Str("output", result.outputString).Err(result.err).Msg("Done execute task")
	if err != nil {
		log.Err(err).Msg("Error while Execute command")
	}
	nc := notificationConfig{}
	for _, n := range c.Notification {
		if n.Name == job.Notification {
			nc = n
		}
	}
	sendNotification(result, nc)
}

func sendNotification(result jobResult, notification notificationConfig) error {
	title := ""
	msg := Message{}
	msg.Priority = 10

	if result.isSuccess() {
		title = "✅ " + result.job.Name
		msg.Priority = -1
	} else {
		title = "❌ " + result.job.Name
	}

	msg.Message = result.outputString
	msg.Title = title

	if result.isSuccess() {
		if notification.Success.Gotify.URL != "" {
			SendGotifyNotification(notification.Success.Gotify.URL, msg)
		}
	} else {
		if notification.Error.Gotify.URL != "" {
			SendGotifyNotification(notification.Error.Gotify.URL, msg)
		}
	}

	return nil
}

func executeCommand(job jobconfig) (jobResult, error) {
	j := jobResult{}
	j.job = job
	var output bytes.Buffer
	cmd := exec.Command("bash", "-c", job.Command)
	cmd.Stdout = &output
	cmd.Stderr = &output
	err := cmd.Run()

	j.outputString = output.String()

	if err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
				j.execCode = status.ExitStatus()
			}
		} else {
			j.err = err
			return j, err
		}
	}

	return j, nil
}
