package configs

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"os"
)

const (
	ConfigFileName string = ".devtool"
)

var (
	ErrConfigNotInitialized error = errors.New("Config file is not initialized")
)

type Config struct {
	// ProjectPath is where all git repositories will be downloaded to
	ProjectPath string
	// VolumePath is where all the persisitant data will be saved to
	VolumePath string
	//
	LoginCredential LoginCredential
	//
	RepositoryConfig map[string]RepositoryConfig
}

// LoginCredential stores the user credential for API request
type LoginCredential struct {
	Username string
	Password string
	Address  string
}

type RepositoryConfig struct {
	Name        string
	URL         string
	Directory   string
	Private     bool
	GitUsername string
	GitPassword string
}

func GetConfig() (*Config, error) {
	file, err := getConfigFile(ConfigFileName)
	if err != nil {
		if err == ErrConfigNotInitialized {
			config, err := initializeConfig(file)
			if err != nil {
				return config, err
			}
		}
	}

	return getConfig(file)
}

func initializeConfig(w io.WriteCloser) (*Config, error) {
	config := &Config{}
	fmt.Printf("Set the project path: ")
	fmt.Scanf("%s", &(config.ProjectPath))

	fmt.Printf("Set the volume path: ")
	fmt.Scanf("%s", &(config.VolumePath))

	var loginCredential LoginCredential
	fmt.Printf("Set login credential username(admin): ")
	fmt.Scanf("%s", &(loginCredential.Username))
	if loginCredential.Username == "" {
		loginCredential.Username = "admin"
	}

	for {
		fmt.Printf("Set login credential password(******): ")
		fmt.Scanf("%s", &(loginCredential.Password))
		if loginCredential.Password != "" {
			break
		}

		fmt.Println("Login credential password must be provided")
	}

	fmt.Printf("Set login address(127.0.0.1): ")
	fmt.Scanf("%s", &(loginCredential.Address))
	if loginCredential.Address == "" {
		loginCredential.Address = "http://127.0.0.1:9000/api/auth"
	} else {
		loginCredential.Address = fmt.Sprintf("http://%s:9000/api/auth", loginCredential.Address)
	}

	config.LoginCredential = loginCredential

	// able to configure multiple project
	// if utils.PromptConfirm("Do you want to configure the repository now?") {
	// 	// configure repository
	// }

	bytes, err := json.Marshal(config)
	if err != nil {
		return nil, err
	}

	_, err = w.Write(bytes)
	if err != nil {
		return nil, err
	}
	return config, nil
}

func getConfig(f io.Reader) (*Config, error) {
	config := &Config{}
	bytes := make([]byte, 0)
	_, err := f.Read(bytes)
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(bytes, &config)
	if err != nil {
		return nil, err
	}
	return config, nil
}

// getConfigFile get the config file handler
func getConfigFile(name string) (*os.File, error) {
	_, err := os.Stat(name)
	if err != nil {
		if errors.Is(err, os.ErrNotExist) {
			//create file
			file, err := os.Create(name)
			if err != nil {
				return nil, fmt.Errorf("fail to create config file: %w", err)
			}

			// first set up the git project path and volume path
			// git credential

			return file, err
		} else {
			return nil, err
		}
	}
	return os.OpenFile(name, os.O_RDWR, 0644)
}
