package main

import (
	"errors"
	"fmt"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	gomail "gopkg.in/mail.v2"
	"gopkg.in/yaml.v3"
	"os"
)

type config struct {
	Software  []software `yaml:"software"`
	StoreFile string     `yaml:"storeFile"`
	SMTP      struct {
		Host     string `yaml:"host"`
		Port     int    `yaml:"port"`
		User     string `yaml:"user"`
		Password string `yaml:"password"`
		From     string `yaml:"from"`
		To       string `yaml:"to"`
	} `yaml:"smtp"`
}
type software struct {
	Name   string `yaml:"name"`
	Plugin string `yaml:"plugin"`
	//URL    string
	Data map[string]string `yaml:"data"`
}

func getConfig() config {
	data, err := os.ReadFile("config.yml")
	if err != nil {
		log.Fatal().Err(err).Msg("cant read config")
	}
	c := config{}
	err = yaml.Unmarshal(data, &c)
	if err != nil {
		log.Fatal().Err(err).Msg("cant pars config file")
	}
	return c
}

type Plugin interface {
	getLastVersion(s software) (string, error)
}

func getPlugin(name string) (Plugin, error) {
	switch name {
	case "github":
		return Github{}, nil
	case "forgejo":
		return Forgejo{}, nil

	}

	return nil, errors.New("cant get plugin")
}

func init() {
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}

func main() {
	log.Info().Msg("Start")
	c := getConfig()
	lastData, err := getLastData(c.StoreFile)
	log.Debug().Interface("data", lastData).Msg("Got LastData")
	if err != nil {
		log.Warn().Err(err).Msg("cant get store")
	}
	for _, s := range c.Software {
		logger := log.With().Str("software", s.Name).Str("plugin", s.Plugin).Interface("data", s.Data).Logger()
		logger.Debug().Msg("start checking for update")
		p, err := getPlugin(s.Plugin)
		if err != nil {
			logger.Error().Err(err).Msg("cant get plugin")
			continue
		}
		version, err := p.getLastVersion(s)
		if err != nil {
			panic(err)
		}
		logger.Info().Str("version", version).Msg("get version")
		if v, ok := lastData.LastVersionen[s.Name]; !ok || v != version {
			err = notifyNewRelease(s, version, c)
			if err != nil {
				panic(err)
			}
			lastData.LastVersionen[s.Name] = version
		} else {
			log.Debug().Msg("Everything up to date")
		}
	}
	err = saveLastData(lastData, c.StoreFile)
	if err != nil {
		panic(err)
	}

	log.Info().Msg("Done")
}

func notifyNewRelease(s software, version string, c config) error {
	log.Info().Interface("software", s).Str("version", version).Msg("inform about new version")
	m := gomail.NewMessage()
	m.SetHeader("From", c.SMTP.From)
	m.SetHeader("To", c.SMTP.To)
	m.SetHeader("Subject", fmt.Sprintf("Release %s %s", s.Name, version))
	m.SetBody("text/plain", fmt.Sprintf("Hello Admin\r\n\r\nthe Software %s is not avalibel in Versio %s please consider to upgrade.", s.Name, version))

	d := gomail.NewDialer(c.SMTP.Host, c.SMTP.Port, c.SMTP.User, c.SMTP.Password)

	err := d.DialAndSend(m)
	if err != nil {
		return err
	}
	return nil
}
