package config

import (
	"fmt"
	"io/fs"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"coopcloud.tech/abra/pkg/log"
)

const MAX_SANITISED_APP_NAME_LENGTH = 45
const MAX_DOCKER_SECRET_LENGTH = 64

var BackupbotLabel = "coop-cloud.backupbot.enabled"

// GetServers retrieves all servers.
func GetServers() ([]string, error) {
	var servers []string

	servers, err := GetAllFoldersInDirectory(SERVERS_DIR)
	if err != nil {
		return servers, err
	}

	var filtered []string
	for _, s := range servers {
		if !strings.HasPrefix(s, ".") {
			filtered = append(filtered, s)
		}
	}

	log.Debugf("retrieved %v servers: %s", len(filtered), filtered)

	return filtered, nil
}

// ReadServerNames retrieves all server names.
func ReadServerNames() ([]string, error) {
	serverNames, err := GetAllFoldersInDirectory(SERVERS_DIR)

	if err != nil {
		return nil, err
	}

	log.Debugf("read %s from %s", strings.Join(serverNames, ","), SERVERS_DIR)

	return serverNames, nil
}

// GetAllFilesInDirectory returns filenames of all files in directory
func GetAllFilesInDirectory(directory string) ([]fs.FileInfo, error) {
	var realFiles []fs.FileInfo

	files, err := ioutil.ReadDir(directory)
	if err != nil {
		return nil, err
	}

	for _, file := range files {
		// Follow any symlinks
		filePath := path.Join(directory, file.Name())

		if filepath.Ext(strings.TrimSpace(filePath)) != ".env" {
			continue
		}

		realPath, err := filepath.EvalSymlinks(filePath)
		if err != nil {
			log.Warnf("broken symlink in your abra config folders: %s", filePath)
		} else {
			realFile, err := os.Stat(realPath)
			if err != nil {
				return nil, err
			}
			if !realFile.IsDir() {
				realFiles = append(realFiles, file)
			}
		}
	}

	return realFiles, nil
}

// GetAllFoldersInDirectory returns both folder and symlink paths
func GetAllFoldersInDirectory(directory string) ([]string, error) {
	var folders []string

	files, err := ioutil.ReadDir(directory)
	if err != nil {
		return nil, err
	}
	if len(files) == 0 {
		return nil, fmt.Errorf("directory is empty: %s", directory)
	}

	for _, file := range files {
		// Check if file is directory or symlink
		if file.IsDir() || file.Mode()&fs.ModeSymlink != 0 {
			filePath := path.Join(directory, file.Name())
			realDir, err := filepath.EvalSymlinks(filePath)
			if err != nil {
				log.Warnf("broken symlink in your abra config folders: %s", filePath)
			} else if stat, err := os.Stat(realDir); err == nil && stat.IsDir() {
				// path is a directory
				folders = append(folders, file.Name())
			}
		}
	}

	return folders, nil
}