package config

import (
	"os"
	"path/filepath"

	"gopkg.in/yaml.v2"
)

type Common struct {
	Minify            bool              `yaml:"minify,omitempty"`
	MinifyWhitespace  bool              `yaml:"minifyWhitespace"`
	MinifyIdentifiers bool              `yaml:"minifyIdentifiers"`
	Bundle            bool              `yaml:"bundle"`
	Sourcemap         bool              `yaml:"sourcemap"`
	Platform          string            `yaml:"platform"`
	Format            string            `yaml:"format"`
	Outdir            string            `yaml:"outdir"`
	JSX               string            `yaml:"jsx"`
	JSXFactory        string            `yaml:"jsxFactory"`
	JSXImportSource   string            `yaml:"jsxImportSource"`
	Loader            map[string]string `yaml:"loader,omitempty"`
	External          []string          `yaml:"external,omitempty"`
}

type Config struct {
	Serve  *ServeConfig `yaml:"serve,omitempty"`
	Build  *BuildConfig `yaml:"build,omitempty"`
	Run    *RunConfig   `yaml:"run,omitempty"`
	Watch  *WatchConfig `yaml:"watch,omitempty"`
	Common `yaml:",inline"`
}

type ServeConfig struct {
	Html   string `yaml:"html"`
	Port   int    `yaml:"port"`
	Common `yaml:",inline"`
}

type BuildConfig struct {
	Common `yaml:",inline"`
}

type RunConfig struct {
	Runtime string `yaml:"runtime"`
	Common  `yaml:",inline"`
}

type WatchConfig struct {
	Paths []string `yaml:"paths"`
}

func GetDefaultConfig() *Config {
	defaultConfig := Common{
		Minify:            false,
		MinifyWhitespace:  false,
		MinifyIdentifiers: false,
		Bundle:            true,
		Sourcemap:         true,
		Platform:          "browser",
		Format:            "esm",
		Outdir:            "public",
		JSX:               "automatic",
		JSXFactory:        "React.createElement",
		JSXImportSource:   "",
		Loader:            map[string]string{},
		External:          []string{},
	}

	return &Config{
		Serve: &ServeConfig{
			Html:   "public/index.html",
			Port:   1234,
			Common: defaultConfig,
		},
		Build: &BuildConfig{
			Common: defaultConfig,
		},
		Run: &RunConfig{
			Runtime: "node",
			Common:  defaultConfig,
		},
		Watch: &WatchConfig{
			Paths: []string{"src/**/*.{ts,tsx,js,jsx}"},
		},
		Common: defaultConfig,
	}
}

func ReadConfig(filename string) (*Config, error) {
	absPath, err := filepath.Abs(filename)
	if err != nil {
		return nil, err
	}

	data, err := os.ReadFile(absPath)
	if err != nil {
		return nil, err
	}

	config := GetDefaultConfig()

	if err := yaml.Unmarshal(data, &config.Build); err != nil {
		return nil, err
	}

	if err := yaml.Unmarshal(data, &config.Serve); err != nil {
		return nil, err
	}

	if err := yaml.Unmarshal(data, &config.Run); err != nil {
		return nil, err
	}

	if err := yaml.Unmarshal(data, &config.Watch); err != nil {
		return nil, err
	}

	if err := yaml.Unmarshal(data, &config); err != nil {
		return nil, err
	}

	return config, nil
}
