/*
Copyright © 2023 Philipp Wolfer <phw@uploadedlobster.com>

Scotty is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.

Scotty is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
Scotty. If not, see <https://www.gnu.org/licenses/>.
*/

package config

import (
	"fmt"
	"sort"

	"github.com/spf13/cast"
	"github.com/spf13/viper"
	"go.uploadedlobster.com/scotty/internal/i18n"
)

type ServiceConfig struct {
	Name         string
	Backend      string
	ConfigValues map[string]any
}

func NewServiceConfig(name string, config *viper.Viper) ServiceConfig {
	service := ServiceConfig{
		Name:         name,
		Backend:      config.GetString("backend"),
		ConfigValues: make(map[string]any),
	}

	for key, val := range config.AllSettings() {
		if key != "backend" {
			service.ConfigValues[key] = val
		}
	}

	return service
}

func (c ServiceConfig) String() string {
	return c.Name
}

func (c *ServiceConfig) GetString(key string) string {
	return cast.ToString(c.ConfigValues[key])
}

func (c *ServiceConfig) GetBool(key string) bool {
	return cast.ToBool(c.ConfigValues[key])
}

func (c *ServiceConfig) IsSet(key string) bool {
	_, ok := c.ConfigValues[key]
	return ok
}

func (c *ServiceConfig) Save() error {
	key := "service." + c.Name
	viper.Set(key+".backend", c.Backend)
	for k, v := range c.ConfigValues {
		viper.Set(key+"."+k, v)
	}
	return WriteConfig()
}

// Deletes the service configuration from the config file
func (c *ServiceConfig) Delete() error {
	key := "service." + c.Name
	return WriteConfig(key)
}

type ServiceList []ServiceConfig

func (l ServiceList) Len() int {
	return len(l)
}

func (l ServiceList) Less(i, j int) bool {
	return l[i].Name < l[j].Name
}

func (l ServiceList) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

func AllServices() map[string]ServiceConfig {
	services := make(map[string]ServiceConfig)
	config := viper.Sub("service")
	if config != nil {
		for k := range config.AllSettings() {
			s := config.Sub(k)
			if s != nil {
				services[k] = NewServiceConfig(k, s)
			}
		}
	}
	return services
}

func AllServicesAsList() ServiceList {
	services := AllServices()
	list := make(ServiceList, 0, len(services))
	for _, s := range services {
		list = append(list, s)
	}
	sort.Sort(list)
	return list
}

func GetService(name string) (ServiceConfig, error) {
	key := "service." + name
	config := viper.Sub(key)
	if config != nil {
		service := NewServiceConfig(name, config)
		return service, nil
	}

	return ServiceConfig{}, fmt.Errorf(i18n.Tr("no service configuration \"%v\"", name))
}