package plugins

import (
	"log"
	"os"
	"path/filepath"

	"gopkg.in/yaml.v3"
)

type pluginFileEntry struct {
	Enable bool        `yaml:"enable"`
	Config interface{} `yaml:"config,omitempty"`
}

type pluginsFileData struct {
	Plugins map[string]pluginFileEntry `yaml:"plugins"`
}

type PluginsFile struct {
	path string
	data pluginsFileData
}

func OpenPluginsFile(dbPath string) (*PluginsFile, error) {
	path := filepath.Join(filepath.Dir(dbPath), "plugins.yaml")
	pf := &PluginsFile{
		path: path,
		data: pluginsFileData{Plugins: make(map[string]pluginFileEntry)},
	}
	raw, err := os.ReadFile(path) // #nosec G304 -- path is filepath.Join(dbDir, "plugins.yaml"), hardcoded filename
	if os.IsNotExist(err) {
		return pf, nil
	}
	if err != nil {
		return nil, err
	}
	if err := yaml.Unmarshal(raw, &pf.data); err != nil {
		return nil, err
	}
	if pf.data.Plugins == nil {
		pf.data.Plugins = make(map[string]pluginFileEntry)
	}
	return pf, nil
}

func (pf *PluginsFile) save() error {
	raw, err := yaml.Marshal(&pf.data)
	if err != nil {
		return err
	}
	return os.WriteFile(pf.path, raw, 0o600)
}

func (pf *PluginsFile) get(id string) (enabled bool, config string, found bool) {
	e, ok := pf.data.Plugins[id]
	if !ok {
		return false, "", false
	}
	if e.Config == nil {
		return e.Enable, "", true
	}
	raw, err := yaml.Marshal(e.Config)
	if err != nil {
		return e.Enable, "", true
	}
	return e.Enable, string(raw), true
}

func (pf *PluginsFile) register(id string, defaultEnabled bool, configText string) {
	if _, ok := pf.data.Plugins[id]; !ok {
		entry := pluginFileEntry{Enable: defaultEnabled}
		if configText != "" {
			var parsed interface{}
			if err := yaml.Unmarshal([]byte(configText), &parsed); err == nil {
				entry.Config = parsed
			}
		}
		pf.data.Plugins[id] = entry
		if err := pf.save(); err != nil {
			log.Printf("plugin %s: register save: %v", id, err)
		}
	}
}

func (pf *PluginsFile) setEnabled(id string, enabled bool) error {
	e := pf.data.Plugins[id]
	e.Enable = enabled
	pf.data.Plugins[id] = e
	return pf.save()
}

func (pf *PluginsFile) setConfig(id string, configText string) error {
	e := pf.data.Plugins[id]
	if configText == "" {
		e.Config = nil
	} else {
		var parsed interface{}
		if err := yaml.Unmarshal([]byte(configText), &parsed); err != nil {
			return err
		}
		e.Config = parsed
	}
	pf.data.Plugins[id] = e
	return pf.save()
}
