package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
)

const defaultPort = 17680

type config struct {
	WikiRoot          string   `json:"wikiRoot"`
	AllowedOrigins    []string `json:"allowedOrigins"`
	Port              int      `json:"port,omitempty"`
	OpenFileCommand   string   `json:"openFileCommand,omitempty"`
	OpenFolderCommand string   `json:"openFolderCommand,omitempty"`
}

// configPath returns the platform-conventional config path.
//
// Windows: %APPDATA%\datascape\companion.json
// Linux:   $XDG_CONFIG_HOME/datascape/companion.json
//          (fallback ~/.config/datascape/companion.json)
func configPath() (string, error) {
	if runtime.GOOS == "windows" {
		appData := os.Getenv("APPDATA")
		if appData == "" {
			return "", errors.New("APPDATA not set")
		}
		return filepath.Join(appData, "datascape", "companion.json"), nil
	}
	if x := os.Getenv("XDG_CONFIG_HOME"); x != "" {
		return filepath.Join(x, "datascape", "companion.json"), nil
	}
	home, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(home, ".config", "datascape", "companion.json"), nil
}

// loadOrInitConfig reads the on-disk config, creating a default file if none
// exists. Returns the resolved config (with port defaulted) and the path.
func loadOrInitConfig() (*config, string, error) {
	p, err := configPath()
	if err != nil {
		return nil, "", err
	}
	data, err := os.ReadFile(p)
	if errors.Is(err, os.ErrNotExist) {
		cfg := &config{AllowedOrigins: []string{}, Port: defaultPort}
		if err := writeConfigFile(p, cfg); err != nil {
			return nil, p, err
		}
		return cfg, p, nil
	}
	if err != nil {
		return nil, p, err
	}
	var cfg config
	if err := json.Unmarshal(data, &cfg); err != nil {
		return nil, p, fmt.Errorf("parse config: %w", err)
	}
	if cfg.Port == 0 {
		cfg.Port = defaultPort
	}
	if cfg.AllowedOrigins == nil {
		cfg.AllowedOrigins = []string{}
	}
	return &cfg, p, nil
}

// writeConfigFile atomically writes cfg to p (write-temp + rename).
func writeConfigFile(p string, cfg *config) error {
	if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
		return err
	}
	out := *cfg
	if out.AllowedOrigins == nil {
		out.AllowedOrigins = []string{}
	}
	data, err := json.MarshalIndent(out, "", "  ")
	if err != nil {
		return err
	}
	tmp := p + ".tmp"
	if err := os.WriteFile(tmp, data, 0644); err != nil {
		return err
	}
	return os.Rename(tmp, p)
}
