package filesystem

import (
	"context"
	"encoding/json"
	"fmt"
	"net/url"
	"os"

	"github.com/pomerium/pomerium/internal/zero/bootstrap/writers"
	"github.com/pomerium/pomerium/pkg/cryptutil"
	cluster_api "github.com/pomerium/pomerium/pkg/zero/cluster"
)

func init() {
	writers.RegisterBuilder("file", newFileWriter)
}

func newFileWriter(uri *url.URL) (writers.ConfigWriter, error) {
	if uri.Host != "" {
		// prevent the common mistake of "file://path/to/file"
		return nil, fmt.Errorf(`invalid file uri %q (did you mean "file:///%s%s"?)`, uri.String(), uri.Host, uri.Path)
	}
	return &fileWriter{
		filePath: uri.Path,
	}, nil
}

type fileWriter struct {
	opts     writers.ConfigWriterOptions
	filePath string
}

// WithOptions implements writers.ConfigWriter.
func (w *fileWriter) WithOptions(opts writers.ConfigWriterOptions) writers.ConfigWriter {
	clone := *w
	clone.opts = opts
	return &clone
}

// WriteConfig implements ConfigWriter.
func (w *fileWriter) WriteConfig(_ context.Context, src *cluster_api.BootstrapConfig) error {
	data, err := json.Marshal(src)
	if err != nil {
		return fmt.Errorf("marshal file config: %w", err)
	}

	if w.opts.Cipher != nil {
		data = cryptutil.Encrypt(w.opts.Cipher, data, nil)
	}
	err = os.WriteFile(w.filePath, data, 0o600)
	if err != nil {
		return fmt.Errorf("write bootstrap config: %w", err)
	}
	return nil
}

var _ writers.ConfigWriter = (*fileWriter)(nil)