package mockenv

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

/*
	Мок-объект для инициализации переменных окружения
*/

var (
	vars = []string{
		"STAGE",
		"SERVICE_NUM",
		"BUS_LOCAL_URL",
		"KAFKA_URL",
		"COMUNDA_URL",
	}
	path, _  = os.Getwd()
	selfPath = `/notify_service/` // Путь к своему проекту
	fileEnv  = ".env"
)

// MockEnv -- мок-объект для переменных окружения
type MockEnv struct {
	dict map[string]string
}

// NewMockEnv -- возвращает новый *MockEnv
func NewMockEnv() *MockEnv {
	sf := &MockEnv{
		dict: make(map[string]string),
	}
	return sf
}

// InitFake -- инициализация фейковыми данными
func (sf *MockEnv) InitFake() {
	sf.dict = make(map[string]string)
	i := 0
	for _, var_ := range vars {
		os.Unsetenv(var_)
		strVal := fmt.Sprint(i)
		os.Setenv(var_, strVal)
		if var_ == "STAGE" {
			os.Unsetenv(var_)
			os.Setenv(var_, "local")
		}
		sf.dict[var_] = strVal
		i++
	}
}

// InitLocal -- читает из локального окружения файл, заполняет переменные
func (sf *MockEnv) InitLocal() error {
	strData, err := sf.readFile()
	if err != nil {
		return fmt.Errorf("MockEnv.InitLocal(): при чтении файла, err=\n\t%w", err)
	}
	dict, err := sf.getPairs(strData)
	if err != nil {
		return fmt.Errorf("MockEnv.InitLocal(): при получении пар ключ:значение, err=\n\t%w", err)
	}
	sf.initEnv(dict)
	sf.dict = dict
	sf.checkStage()
	return nil
}

// Проверяет наличие поля STAGE
func (sf *MockEnv) checkStage() {
	stage, ok := sf.dict["STAGE"]
	if !ok {
		panic(fmt.Errorf("MockEnv.checkStage(): не установлена переменная STAGE"))
	}
	if stage != "local" {
		panic(fmt.Errorf("MockEnv.checkStage(): не локальное окружение, STAGE=%q", stage))
	}
}

// Инициализирует все заданные переменные окружения
func (sf *MockEnv) initEnv(mapEnv map[string]string) {
	// Здесь не должен быть nil НИКОГДА
	for key, value := range mapEnv {
		os.Unsetenv(key)
		os.Setenv(key, value)
	}
}

// Готовит словарь значений
func (sf *MockEnv) getPairs(strData string) (map[string]string, error) {
	lstData := strings.Split(strData, "\n")
	mapEnv := make(map[string]string)
	for _, line := range lstData {
		if line == "" {
			continue
		}
		lstPart := strings.Split(line, `="`)
		if len(lstPart) != 2 {
			return nil, fmt.Errorf("MockEnv.getPairs(): в параметре %q неправильный формат", line)
		}
		key := lstPart[0]
		if key == "" {
			return nil, fmt.Errorf("MockEnv.getPairs(): пустой ключ в строке %q", line)
		}
		value := lstPart[1]
		value = value[:len(value)-1]
		if value == "" {
			return nil, fmt.Errorf("MockEnv.getPairs(): пустое значение в строке %q", line)
		}
		mapEnv[key] = value
	}
	if len(mapEnv) == 0 {
		return nil, fmt.Errorf("MockEnv.getPairs(): len dict == 0")
	}
	return mapEnv, nil
}

// Читает файл окружения
func (sf *MockEnv) readFile() (string, error) {
	if !strings.Contains(path, selfPath) {
		return "", fmt.Errorf("MockEnv.readFile(): неправильный путь проекта")
	}
	pt := path
	lstPath := strings.Split(pt, selfPath)
	if len(lstPath) != 2 {
		return "", fmt.Errorf("MockEnv.readFile(): плохой путь к файлу окружения %q", path)
	}
	pt = lstPath[0]
	fileName := pt + selfPath + fileEnv
	binData, err := ioutil.ReadFile(fileName)
	if err != nil {
		return "", fmt.Errorf("MockEnv.readFile(): при чтении файла %q .env, err=%w", fileName, err)
	}
	return string(binData), nil
}

// Unset -- удаляет все переменные окружения сервиса
func (sf *MockEnv) Unset() {
	for key := range sf.dict {
		os.Unsetenv(key)
	}
}
