package config

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/BurntSushi/toml"
)

const (
	configDirPath  = "data"
	configFileJSON = "data.json"
	configFileTOML = "data.toml"
)

var ErrConfigNotFound = errors.New("config not found")

type Config interface {
	Install() error
	Update() error
	Clean() error
	Diff() error
	Download() error
	Validate() error
}

type ConfigApps struct {
	Apps map[string]App `json:"apps" toml:"apps"`
}

// Read from file
type App struct {
	Paths []Path `json:"paths" toml:"paths"`
}

type Path struct {
	Internal string `json:"internal" toml:"internal"`
	External string `json:"external,omitempty" toml:"external"`
	URL      string `json:"url,omitempty" toml:"url"`
}

// LoadConfig return config, configDemo
func LoadConfig(path string) (*ConfigReal, *ConfigDemo, error) {
	cfgReal, cfgDemo, err := loadConfigJSON(path)
	if err == nil {
		return cfgReal, cfgDemo, nil
	}

	cfgReal, cfgDemo, err = loadConfigTOML(path)
	if err == nil {
		return cfgReal, cfgDemo, nil
	}

	return nil, nil, ErrConfigNotFound
}

func loadConfigJSON(path string) (*ConfigReal, *ConfigDemo, error) {
	configPathJSON := filepath.Join(path, configDirPath, configFileJSON)

	bytes, err := os.ReadFile(configPathJSON)
	if err != nil {
		return nil, nil, fmt.Errorf("os: failed to read file [%s]: %w", configPathJSON, err)
	}

	var cfgApps ConfigApps
	if err = json.Unmarshal(bytes, &cfgApps); err != nil {
		return nil, nil, fmt.Errorf("json: failed to unmarshal: %w", err)
	}

	cfgReal := ConfigReal{
		httpClient: &http.Client{
			Timeout: time.Second * 5,
		},
		ConfigApps: cfgApps,
	}

	cfgDemo := ConfigDemo{
		ConfigApps: cfgApps,
	}

	return &cfgReal, &cfgDemo, nil
}

func loadConfigTOML(path string) (*ConfigReal, *ConfigDemo, error) {
	configPathTOML := filepath.Join(path, configDirPath, configFileTOML)

	bytes, err := os.ReadFile(configPathTOML)
	if err != nil {
		return nil, nil, fmt.Errorf("os: failed to read file [%s]: %w", configPathTOML, err)
	}

	var cfgApps ConfigApps
	if err := toml.Unmarshal(bytes, &cfgApps); err != nil {
		return nil, nil, fmt.Errorf("toml: failed to decode: %w", err)
	}

	cfgReal := ConfigReal{
		httpClient: &http.Client{
			Timeout: time.Second * 5,
		},
		ConfigApps: cfgApps,
	}

	cfgDemo := ConfigDemo{
		ConfigApps: cfgApps,
	}

	return &cfgReal, &cfgDemo, nil
}
