package main

import (
	"bytes"
	"compress/gzip"
	"io"
	"os"
	"path/filepath"

	restful "github.com/emicklei/go-restful"
	"gopkg.in/yaml.v2"
	"m.cluseau.fr/go/httperr"
	"novit.tech/direktil/pkg/localconfig"
)

func wsFetchConfig(req *restful.Request, resp *restful.Response) {
	cfg, err := readConfig()
	if err != nil {
		if os.IsNotExist(err) {
			wsNotFound(resp)
		} else {
			wsError(resp, httperr.Internal(err))
		}
		return
	}

	resp.WriteEntity(cfg)
}

func wsUploadConfig(req *restful.Request, resp *restful.Response) {
	cfg := &localconfig.Config{}
	if err := req.ReadEntity(cfg); err != nil {
		wsError(resp, httperr.BadRequest(err.Error()))
		return
	}

	cfgBytes, err := yaml.Marshal(cfg)
	if err != nil {
		wsError(resp, err)
		return
	}

	err = writeNewConfig(cfgBytes)
	if err != nil {
		wsError(resp, err)
		return
	}

	resp.WriteEntity(true)
}

func writeNewConfig(cfgBytes []byte) (err error) {
	out, err := os.CreateTemp(*dataDir, ".config-upload")
	if err != nil {
		return
	}

	defer os.Remove(out.Name())

	_, err = io.Copy(out, bytes.NewReader(cfgBytes))
	out.Close()
	if err != nil {
		return
	}

	cfgPath := configFilePath()
	in, err := os.Open(cfgPath)

	if err != nil {
		if os.IsNotExist(err) {
			// nothing to backup
		} else {
			return // real error
		}
	} else {
		err = backupCurrentConfig(in)
		if err != nil {
			return
		}
	}

	err = os.Rename(out.Name(), cfgPath)

	updateState()
	go updateCache()

	return
}

func backupCurrentConfig(in io.ReadCloser) (err error) {
	archivesPath := filepath.Join(*dataDir, "archives")

	err = os.MkdirAll(archivesPath, 0700)
	if err != nil {
		return
	}

	backupPath := filepath.Join(archivesPath, "config."+ulid()+".yaml.gz")

	bck, err := os.Create(backupPath)
	if err != nil {
		return
	}

	defer bck.Close()

	gz, err := gzip.NewWriterLevel(bck, 2)
	if err != nil {
		return
	}

	_, err = io.Copy(gz, in)
	gz.Close()
	in.Close()

	return
}
