package secrets_storage

import (
	"fmt"
	"kube-forge/internal/config"
	"kube-forge/internal/kubernetes_client"
	"kube-forge/internal/templates"
	"regexp"
	"strings"
)

func InitVault() {
	_, err := kubernetes_client.GetPodByName("vault-0", "secrets-storage")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	err = commandToInitVault()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println("Vault initialized")
	templates.ApplyVaultInitKeysTemplate()
}

func AddKubernetesLocalIntegration() {
	_, err := kubernetes_client.GetPodByName("vault-0", "secrets-storage")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	err = commandToAddKubernetesLocalIntegration()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println("Vault local Kubernetes integration added")
}

func UnsealVault() {
	_, err := kubernetes_client.GetPodByName("vault-0", "secrets-storage")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	commandToUnsealVault()
}

func commandToInitVault() error {
	config := config.GetConfig()
	commandArray := []string{
		"vault", "operator", "init",
		fmt.Sprintf("-key-shares=%d", config.Modules.SecretsStorage.KeyShares),
		fmt.Sprintf("-key-threshold=%d", config.Modules.SecretsStorage.KeyThreshold),
	}
	output, err := kubernetes_client.ExecuteCommandInPodContainer(
		commandArray, "secrets-storage", "vault-0", "vault",
	)
	if err != nil && strings.Contains(output, "Vault is already initialized") {
		return VaultAlreadyInitialised
	}

	unsealKeys, rootToken := parseVaultInitKeys(output)
	config.Modules.SecretsStorage.UnsealKeys = unsealKeys
	config.Modules.SecretsStorage.AuthToken = rootToken
	return nil
}

func parseVaultInitKeys(input string) ([]string, string) {
	unsealKeyPattern := regexp.MustCompile(`Unseal Key \d+: (\S+)`)
	rootTokenPattern := regexp.MustCompile(`Initial Root Token: (\S+)`)

	unsealKeysMatches := unsealKeyPattern.FindAllStringSubmatch(input, -1)
	var unsealKeys []string
	for _, match := range unsealKeysMatches {
		unsealKeys = append(unsealKeys, match[1])
	}

	rootTokenMatches := rootTokenPattern.FindStringSubmatch(input)
	rootToken := rootTokenMatches[1]

	return unsealKeys, rootToken
}

func commandToUnsealVault() {
	config := config.GetConfig()

	for _, unsealKey := range config.Modules.SecretsStorage.UnsealKeys {
		commandArray := []string{"vault", "operator", "unseal", unsealKey}
		kubernetes_client.ExecuteCommandInPodContainer(
			commandArray, "secrets-storage", "vault-0", "vault",
		)
	}
	fmt.Println("Vault unsealed")
}

func commandToAddKubernetesLocalIntegration() error {
	config := config.GetConfig()

	commandArray := []string{"vault", "login", config.Modules.SecretsStorage.AuthToken}
	output, err := kubernetes_client.ExecuteCommandInPodContainer(
		commandArray, "secrets-storage", "vault-0", "vault",
	)
	if err != nil && strings.Contains(output, "permission denied") {
		return IncorrectCredentials
	}
	commandArray = []string{"vault", "auth", "enable", "-local", "-path=kubernetes-local", "kubernetes"}
	output, err = kubernetes_client.ExecuteCommandInPodContainer(
		commandArray, "secrets-storage", "vault-0", "vault",
	)
	kubernetesInternalServiceAddr, err := kubernetes_client.GetEnvVariableFromPodContainer(
		"KUBERNETES_PORT_443_TCP_ADDR",
		"secrets-storage",
		"vault-0",
		"vault",
	)
	if err != nil {
		return err
	}
	commandArray = []string{
		"vault", "write", "auth/kubernetes-local/config",
		fmt.Sprintf("kubernetes_host=https://%s:443", kubernetesInternalServiceAddr),
	}
	output, err = kubernetes_client.ExecuteCommandInPodContainer(
		commandArray, "secrets-storage", "vault-0", "vault",
	)
	return nil
}
