package executor

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
)

var RemoveForcePrefix = []string{"rm", "-rf"}

// BasicCommandExists 判定命令是否存在
func BasicCommandExists(commandName string) bool {

	cmd := exec.Command("command", "-v", commandName)
	err := cmd.Run()
	if err != nil {
		log.DebugF("指令 %s 不存在 => %s", commandName, err.Error())
		return false
	} else {
		return true
	}
}

// BasicCommandExistsBatch 判定批量命令是否存在
func BasicCommandExistsBatch(commandNameList []string) (bool, string) {

	for _, commandName := range commandNameList {
		if !BasicCommandExists(commandName) {
			return false, commandName
		}
	}

	return true, ""
}

// BasicCommandExistByPath 根据路径判定 命令是否存在
func BasicCommandExistByPath(commandName string) bool {

	if BasicFileExistInFolder(commandName, "/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "bin", "/snap/bin") {
		return true
	}

	return false
}

// BasicFileExistInFolder 查询fileName是否存在于目录folderList中，如果存在返回true，不存在返回false
func BasicFileExistInFolder(fileName string, folderList ...string) bool {

	for _, folder := range folderList {
		if BasicFolderExists(folder) {
			// is folder
			ok, _ := PipelineCommandExecutor([][]string{
				{
					"ls",
					folder,
				},
				{
					"grep",
					"-c",
					fileName,
				},
			})
			if ok {
				return true
			}

		} else {
			// it's a file
			ok, _ := PipelineCommandExecutor([][]string{
				{
					"echo",
					folder,
				},
				{
					"grep",
					"-c",
					fileName,
				},
			})
			if ok {
				return true
			}
		}
	}

	return false
}

func BasicGrepItemInFile(item string, fileName string) bool {

	if !BasicFileExistAndNotNull(fileName) {
		log.ErrorF("[BasicGrepItemInFile] - fileName [ %s ] not exits !", fileName)
		return false
	}

	ok, _ := PipelineCommandExecutor([][]string{
		{
			"cat",
			fileName,
		},
		{
			"grep",
			"-q",
			item,
		},
	})

	if ok {
		return true
	}

	return false
}

func BasicFindContentInFile(content string, fileName string) bool {
	// Open the file
	file, err := os.Open(fileName)
	if err != nil {
		log.ErrorF("[BasicFindContentInFile] - file not exits ！")
		return false
	}
	defer file.Close()

	// Create a scanner to read the file line by line
	scanner := bufio.NewScanner(file)

	// Set the split function for the scanner
	scanner.Split(bufio.ScanLines)

	// Iterate over the lines of the file
	for scanner.Scan() {
		// Get the current line
		line := scanner.Text()

		// Check if the current line contains the search term
		if strings.Contains(line, content) {
			return true
		}
	}

	// Check for any errors that occurred during scanning
	if err := scanner.Err(); err != nil {
		log.ErrorF("[BasicFindContentInFile] - scanner error ! %s", err.Error())
	}

	return false
}

func BasicFindDeleteContendLineInFile(content string, fileName string) bool {

	// Open the file
	file, err := os.Open(fileName)
	if err != nil {
		log.ErrorF("[FindDeleteContendLineInFile] - file not exits ！")
		return false
	}
	defer file.Close()

	// Create a scanner to read the file line by line
	scanner := bufio.NewScanner(file)

	// Set the split function for the scanner
	scanner.Split(bufio.ScanLines)

	// 创建一个新的文件内容变量
	var newContent string

	// Iterate over the lines of the file
	for scanner.Scan() {
		// Get the current line
		line := scanner.Text()

		// Check if the current line contains the search term
		if !strings.Contains(line, content) {
			newContent += line + "\n"
		}
	}

	// Check for any errors that occurred during scanning
	if err := scanner.Err(); err != nil {
		log.ErrorF("[BasicFindContentInFile] - scanner error ! %s", err.Error())
		return false
	}

	// 将修改后的内容写回文件
	err = os.WriteFile(fileName, []byte(newContent), os.ModePerm)
	if err != nil {
		log.ErrorF("[FindDeleteContendLineInFile] - write file %s error with contend %s", fileName, newContent)
		return false
	}

	return true
}

func BasicDockerImageExists(imageName, imageVersion string) bool {

	if !BasicCommandExistByPath("docker") {
		return false
	}

	ok, _ := PipelineCommandExecutor([][]string{
		{
			"docker",
			"image",
			"ls",
		},
		{
			"grep",
			imageName,
		},
		{
			"grep",
			"-q",
			imageVersion,
		},
	})

	if !ok {
		return false
	}

	return true
}

func BasicInstallSoftwares(installPrefix []string, isStrict bool, softwares ...string) (bool, []string) {

	var installLog []string

	for _, software := range softwares {
		log.DebugF("[BasicInstallSoftwares] - going to install [ %s ]", software)

		if !PureResultSingleExecute(append(installPrefix, software)) {

			failedInstall := fmt.Sprintf("[BasicInstallSoftwares] - software of [ %s ] install failed !", software)
			installLog = append(installLog, failedInstall)

			if isStrict {
				return false, installLog
			}
		}

		successInstall := fmt.Sprintf("[BasicInstallSoftwares] - software of [ %s ] install success !", software)
		installLog = append(installLog, successInstall)
	}

	return true, installLog
}

// BasicReplace 基础替换命令
func BasicReplace(filename string, origin string, replace string) bool {

	// 暂不添加
	//if !BasicFileExistAndNotNull(filename) {
	//	log.DebugF("文件替换")
	//}

	cmd := exec.Command("sed", "-i", "s/"+origin+"/"+replace+"/g", filename)
	err := cmd.Run()
	if err != nil {
		log.DebugF("替换文件 %s ，从 [%s] => [%s] 错误！", filename, origin, replace)
		return false
	} else {
		return true
	}
}

func BasicRemoveFolderComplete(folderName string) bool {

	if !BasicFileExists(folderName) || !BasicFolderExists(folderName) {
		log.DebugF("[BasicRemoveFolderComplete] - file or folder of [%s] not exists !", folderName)
		return true
	}

	cmd := exec.Command("rm", "-rf", folderName)
	err := cmd.Run()
	if err != nil {
		log.DebugF("删除 %s 失败！", folderName)
		return false
	} else {
		return true
	}
}

// BasicFileExists 检测文件是否存在
func BasicFileExists(filename string) bool {

	cmd := exec.Command("test", "-f", filename)
	err := cmd.Run()
	if err != nil {
		log.DebugF("文件 %s 不存在！", filename)
		return false
	} else {
		return true
	}
}

// BasicFileExistAndNotNull 文件不为空返回true 文件为空返回false
func BasicFileExistAndNotNull(filename string) bool {

	cmd := exec.Command("test", "-s", filename)
	err := cmd.Run()
	if err != nil {
		log.DebugF("文件 %s 为空！", filename)
		return false
	} else {
		return true
	}
}

func BasicFolderExists(folderName string) bool {

	cmd := exec.Command("test", "-d", folderName)
	err := cmd.Run()
	if err != nil {
		log.DebugF("目录 %s 不存在！", folderName)
		return false
	} else {
		return true
	}
}

func BasicCreateFolder(folderName string) bool {
	cmd := exec.Command("test", "-d", folderName)
	err := cmd.Run()
	if err == nil {
		log.DebugF("folder %s already exists !", folderName)
		return true
	}

	cmd2 := exec.Command("mkdir", "-p", folderName)
	err = cmd2.Run()
	if err != nil {
		log.ErrorF("folder %s create error!", folderName)
		return false
	} else {
		log.DebugF("folder %s create success!", folderName)
		return true
	}
}

// BasicPrettyPrint 打印执行结果
func BasicPrettyPrint(resultOk bool, resultLog []string) {
	fmt.Printf("resultOK is => %#v\n", resultOk)
	if resultLog == nil || len(resultLog) == 0 {
		return
	}
	for _, s := range resultLog {
		fmt.Println(s)
		fmt.Println()
	}
}

// BasicSystemdShutdown 使用Systemd关闭服务,会判定服务器是否存在
func BasicSystemdShutdown(serviceName string) (ok bool, resultLog []string) {

	if !strings.HasSuffix(serviceName, ".service") {
		serviceName = serviceName + ".service"
	}

	// 检查是否存在
	existService := BasicFileExistInFolder(serviceName, "/lib/systemd/system/",
		"/etc/systemd/system")
	if !existService {
		return true, []string{
			serviceName,
			"该服务不存在！",
		}
	}

	// 关闭
	var shutDownCommand = [][]string{
		{
			"systemctl",
			"stop",
			serviceName,
		},
		{
			"sleep",
			"1",
		},
		{
			"systemctl",
			"disable",
			serviceName,
		},
	}

	resultOK := PureResultSingleExecuteBatch(shutDownCommand)

	return resultOK, resultLog
}

// BasicSystemdUp 使用Systemd启动服务,会判定服务器是否存在
func BasicSystemdUp(serviceName string) (ok bool, resultLog []string) {

	if !strings.HasSuffix(serviceName, ".service") {
		serviceName = serviceName + ".service"
	}
	// 检查是否存在
	existService := BasicFileExistInFolder(serviceName, "/lib/systemd/system/",
		"/etc/systemd/system")
	if !existService {
		return true, []string{
			serviceName,
			"该服务不存在！",
		}
	}

	// 关闭
	var shutDownCommand = [][]string{
		{
			"systemctl",
			"start",
			serviceName,
		},
		{
			"sleep",
			"1",
		},
		{
			"systemctl",
			"enable",
			serviceName,
		},
	}

	resultOK := PureResultSingleExecuteBatch(shutDownCommand)

	return resultOK, resultLog
}

// BasicTransPipelineCommand 转换手写的管道命令为可执行的形式
func BasicTransPipelineCommand(pipelineString string) (pipelineCommand [][]string) {

	var pipelineCommandC [][]string
	split := strings.Split(pipelineString, "|")
	if len(split) == 0 {
		log.WarnF("输入的pipelineString有误！ %s", pipelineString)
		return pipelineCommandC
	}

	for _, s := range split {
		// 去除掉无效的空行
		singleCommand := strings.Split(s, " ")
		var realSingleCommand []string

		for i := range singleCommand {
			if singleCommand[i] != "" {
				realSingleCommand = append(realSingleCommand, singleCommand[i])
			}
		}
		pipelineCommandC = append(pipelineCommandC, realSingleCommand)
	}

	return pipelineCommandC
}

func BasicConvertBufferToSlice(outputBuffer bytes.Buffer) (resultLog []string) {

	s := outputBuffer.String()
	split := strings.Split(s, "\n")

	return split

}

// BasicDownloadFile 从目标地址下载文件到目的地，并检测文件是否下载成功
func BasicDownloadFile(downloadUrl, desFile string) (downloadOk bool, resultLog []string) {

	// wget or curl download
	var ok bool
	if BasicCommandExistByPath("wget") {

		ok, resultLog = AllCommandExecutor([]string{
			"wget",
			"--no-check-certificate",
			"--timeout=5",
			downloadUrl,
			"-qO",
			desFile,
		})

	} else if BasicCommandExistByPath("curl") {
		ok, resultLog = AllCommandExecutor([]string{
			"curl",
			"-o",
			desFile,
			"--insecure",
			"--max-time",
			"5",
			downloadUrl,
		})

	} else {
		sprintf := fmt.Sprintf("[BasicDownloadFile] - neither wget or curl exists ! can't download file [ %s ] from [ %s ]", desFile, downloadUrl)
		log.Error(sprintf)
		return false, []string{
			sprintf,
		}
	}

	errLog := fmt.Sprintf("[BasicDownloadFile] - download file [ %s ] from [ %s ] failed !", desFile, downloadUrl)
	if !ok {
		log.Error(errLog)
		return false, []string{
			errLog,
		}
	}
	// check file exists
	existAndNotNull := BasicFileExistAndNotNull(desFile)
	if !existAndNotNull {
		return false, []string{
			errLog,
			"[BasicDownloadFile] - file not exist !",
		}
	}

	return true, nil
}

// BasicAppendSourceToFile 将源文件的内容添加到目标文件，使用golang标准库完成，跨平台、安全性更强
func BasicAppendSourceToFile(sourceFile, targetFile string) bool {

	// 打开源文件
	source, err := os.Open(sourceFile)
	if err != nil {
		log.ErrorF("[BasicAppendSourceToFile] - error open source file => %s, error is %s", sourceFile, err.Error())
		return false
	}
	defer source.Close()

	// 打开目标文件，如果不存在则创建，如果存在则在末尾追加
	target, err := os.OpenFile(targetFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.ErrorF("[BasicAppendSourceToFile] - error open target file => %s, error is %s", sourceFile, err.Error())
		return false
	}
	defer target.Close()

	// 将源文件内容复制到目标文件
	_, err = io.Copy(target, source)
	if err != nil {
		log.ErrorF("[BasicAppendSourceToFile] - Error appending to target file: %s", err.Error())
		return false
	}

	return true
}

// BasicAppendContentToFile 向目标文件中追加写入一些内容
func BasicAppendContentToFile(content string, targetFile string) bool {

	// 打开文件用于追加。如果文件不存在，将会创建一个新文件。
	file, err := os.OpenFile(targetFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.ErrorF("[BasicAppendContentToFile] - Error opening file: %s , error is %s", targetFile, err.Error())
		return false
	}
	defer file.Close() // 确保文件最终被关闭

	// 写入内容到文件
	if _, err := file.WriteString(content); err != nil {
		log.ErrorF("[BasicAppendContentToFile] - Error writing to file: %s , error is %s", targetFile, err.Error())
		return false
	}

	return true
}

// BasicAppendNullToFile 清空一个文件
func BasicAppendNullToFile(targetFile string) bool {

	// 使用os.O_TRUNC清空文件内容
	file, err := os.OpenFile(targetFile, os.O_TRUNC|os.O_WRONLY, 0644)
	if err != nil {
		log.ErrorF("[BasicAppendNullToFile] - Error opening file: %s, error is %s", targetFile, err.Error())
		return false
	}
	defer file.Close() // 确保在函数退出前关闭文件

	return true
}

func BasicWordSpaceCompletion(source string, totalLength int) string {
	sourceLength := len(source)

	if sourceLength >= totalLength {
		return source
	}

	for i := 0; i < totalLength-sourceLength; i++ {
		source += " "
	}

	return source
}
