package a_executor

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"golang.org/x/net/proxy"
	"io"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"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 {

	if fileName == "" {
		return false // If the file name is empty, we cannot check for existence.
	}

	for _, folder := range folderList {
		if folder == "" {
			continue // Skip empty folders.
		}
		if BasicFolderExists(folder) {
			// is folder
			ok, _ := PipelineCommandExecutor([][]string{
				{
					"ls",
					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 BasicFindAndDeleteContendLineInFile(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 BasicFindContentInCommandOutput(hardCodeCommand string, content string) (bool, []string) {
	ok, resultLog := HardCodeCommandExecutor(hardCodeCommand)
	if !ok {
		log.ErrorF("[BasicFindContentInCommandOutput] - command error ! => %v", resultLog)
		return false, nil
	}

	return BasicFindContentInList(content, resultLog), resultLog
}

func BasicFindContentInList(content string, list []string) bool {
	for _, item := range list {
		if strings.Contains(item, content) {
			return true
		}
	}
	return false
}

func BasicDockerImageExistByFullName(imageFullName string) bool {

	var imageVersion string

	split := strings.Split(imageFullName, ":")
	imageVersion = split[len(split)-1]

	imageFullName = strings.TrimSuffix(imageFullName, ":"+imageVersion)

	//log.DebugF("[BasicDockerImageExistByFullName] -- %s  %s", imageFullName, imageVersion)
	return BasicDockerImageExists(imageFullName, imageVersion)
}

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 BasicInstallSoftware(installPrefix []string, isStrict bool, softwares ...string) (bool, []string) {

	var installLog []string

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

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

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

			if isStrict {
				return false, installLog
			}
		}

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

	return true, installLog
}

// BasicReplace 将文件中origin字段全部替换为replace
func BasicReplace(filename string, origin string, replace string) bool {

	if !BasicFileExistAndNotNull(filename) {
		log.WarnF("文件替换 文件不存在 %s", filename)
		return false
	}

	// 打开文件
	file, err := os.OpenFile(filename, os.O_RDWR, 0644)
	if err != nil {
		fmt.Printf("error opening file: %v\n", err)
		return false
	}

	// 创建一个临时文件用于存储替换后的内容
	tempFilename := filename + ".tmp"
	tempFile, err := os.Create(tempFilename)
	if err != nil {
		fmt.Printf("error creating temp file: %v\n", err)
		return false
	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()

		// 使用正则表达式替换，以支持多种替换场景（如部分词、多行等）
		re := regexp.MustCompile(fmt.Sprintf("(\\b%s\\b)|(^%s)|(%s$)", origin, origin, replace))
		newLine := re.ReplaceAllString(line, replace)

		// 写入替换后的内容到临时文件
		_, err := tempFile.WriteString(newLine + "\n")
		if err != nil {
			fmt.Printf("error writing to temp file: %v\n", err)
			return false
		}
	}

	// 检查是否有错误发生
	if err := scanner.Err(); err != nil {
		fmt.Printf("error reading from file: %v\n", err)
		return false
	}

	err = file.Close()
	if err != nil {
		log.ErrorF("error closing file: %v\n", err)
		return false
	}
	err = tempFile.Close()
	if err != nil {
		log.ErrorF("error closing file: %v\n", err)
		return false
	}

	// 移动文件名，指向新的替换后的文件
	err = os.Remove(filename)
	if err != nil {
		log.ErrorF("error removing file: %v\n", err)
		return false
	}

	err = os.Rename(tempFilename, filename)
	if err != nil {
		fmt.Printf("error renaming file: %v\n", err)
		return false
	}

	// 返回成功标志
	return true

}

// BasicReplaceBySed 基础替换命令
func BasicReplaceBySed(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 {

	err := filepath.Walk(folderName,
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if !info.IsDir() {
				return os.Remove(path)
			}
			return nil
		})
	if err != nil {
		return false
	}
	err = os.RemoveAll(folderName)
	if err != nil {
		return false
	}
	return true
}

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

	if filename == "" {
		return false // An empty string does not correspond to a valid file.
	}
	_, err := os.Stat(filename)
	if err != nil {
		switch err.(type) {
		case *os.PathError:
			// If the error is because the path doesn't exist, return false.
			if errors.Is(err.(*os.PathError).Err, os.ErrNotExist) {
				log.DebugF("文件 %s 不存在！", filename)
				return false
			}
		case nil:
			return true
		default:
			// Handle other types of errors as appropriate for your use case.
			return false
		}
	}
	return true
}

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

	// Check if the file exists
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		log.DebugF("文件 %s 不存在！", filename)
		return false
	}

	// Open the file for reading
	file, err := os.Open(filename)
	defer file.Close()
	if err != nil {
		log.DebugF("文件 %s 打开有误！", filename)
		return false // Handle error according to your needs
	}

	// Get the file size
	info, _ := file.Stat()
	size := info.Size()

	// Check if the file is not empty
	return size > 0
}

func BasicFolderExists(folderName string) bool {

	fi, err := os.Stat(folderName)
	if err != nil {
		if os.IsNotExist(err) {
			// 目标路径不存在
			log.WarnF("[BasicFolderExists] - 目录 %s 不存在！", folderName)
			return false
		}
		// 其他错误
		return false
	}

	// 判断是否为目录
	return fi.IsDir()
}

func BasicCreateFolder(folderName string) bool {
	// 检查目录是否存在
	if _, err := os.Stat(folderName); os.IsNotExist(err) {
		// 目录不存在，创建目录
		err := os.MkdirAll(folderName, os.ModePerm)
		if err != nil {
			// 如果创建目录失败，返回false
			return false
		}
	}
	// 目录存在或者成功创建，返回true
	return true
}

func BasicRemoveFileOrFolder(folderName string) bool {
	// Check if the folder exists
	if _, err := os.Stat(folderName); os.IsNotExist(err) {
		return true // folder does not exist
	}

	// Folder exists, remove it
	err := os.Remove(folderName)
	if err != nil {
		// Handle error
		return false
	}

	return true // folder was removed
}

// 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

}

func BasicDownloadFile(downloadUrl string, socksProxyUrl string, proxyUser string, proxyPass string, desFile string) (downloadOk bool, resultLog []string) {
	// 解析下载URL
	_, err := url.Parse(downloadUrl)
	if err != nil {
		resultLog = append(resultLog, "Error parsing download URL: "+err.Error())
		return false, resultLog
	}

	// 创建文件
	out, err := os.Create(desFile)
	if err != nil {
		resultLog = append(resultLog, "Error creating file: "+err.Error())
		return false, resultLog
	}
	defer out.Close()

	// 创建HTTP客户端
	client := &http.Client{}

	// 如果提供了代理URL
	if socksProxyUrl != "" {
		// 解析代理URL
		parsedProxyUrl, err := url.Parse(socksProxyUrl)
		if err != nil {
			resultLog = append(resultLog, "Error parsing proxy URL: "+err.Error())
			return false, resultLog
		}

		// 使用SOCKS5代理
		auth := &proxy.Auth{User: proxyUser, Password: proxyPass}
		dialer, err := proxy.SOCKS5("tcp", parsedProxyUrl.Host, auth, proxy.Direct)
		if err != nil {
			resultLog = append(resultLog, "Error creating SOCKS5 dialer: "+err.Error())
			return false, resultLog
		}

		// 设置HTTP和HTTPS代理
		httpTransport := &http.Transport{
			Dial: dialer.Dial,
		}
		client.Transport = httpTransport
	}

	// 发送HTTP GET请求
	resp, err := client.Get(downloadUrl)
	if err != nil {
		resultLog = append(resultLog, "Error making GET request: "+err.Error())
		return false, resultLog
	}
	defer resp.Body.Close()

	// 检查HTTP响应状态码
	if resp.StatusCode != http.StatusOK {
		resultLog = append(resultLog, "Server returned HTTP status "+resp.Status)
		return false, resultLog
	}

	// 将HTTP响应内容写入文件
	_, err = io.Copy(out, resp.Body)
	if err != nil {
		resultLog = append(resultLog, "Error writing to file: "+err.Error())
		return false, resultLog
	}

	// check file exists
	existAndNotNull := BasicFileExistAndNotNull(desFile)
	if !existAndNotNull {
		return false, []string{
			"[BasicDownloadFile] - file not exist  download error!",
		}
	}

	return true, resultLog
}

// BasicDownloadFileByCurl 从目标地址下载文件到目的地，并检测文件是否下载成功
func BasicDownloadFileByCurl(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("[BasicDownloadFileByCurl] - neither wget or curl exists ! can't download file [ %s ] from [ %s ]", desFile, downloadUrl)
		log.Error(sprintf)
		return false, []string{
			sprintf,
		}
	}

	errLog := fmt.Sprintf("[BasicDownloadFileByCurl] - 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,
			"[BasicDownloadFileByCurl] - file not exist !",
		}
	}

	return true, nil
}

func BasicDownloadFileWithProxy(downloadUrl, proxyUrl, desFile string) (downloadOk bool, resultLog []string) {

	var ok bool
	if !BasicCommandExistByPath("curl") {
		return false, []string{
			"curl not exits!",
		}
	}

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

	errLog := fmt.Sprintf("[BasicDownloadFileWithProxy] - download file [ %s ] with proxy [ %s ] from [ %s ] failed !", desFile, proxyUrl, downloadUrl)
	if !ok {
		log.Error(errLog)
		return false, []string{
			errLog,
		}
	}
	// check file exists
	existAndNotNull := BasicFileExistAndNotNull(desFile)
	if !existAndNotNull {
		return false, []string{
			errLog,
			"[BasicDownloadFileByCurl] - 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
}

// BasicAppendOverwriteContentToFile 向目标文件中写入一些内容,覆盖源文件
func BasicAppendOverwriteContentToFile(content string, targetFile string) bool {

	err := os.Remove(targetFile)
	if err != nil {
		log.WarnF("[BasicAppendOverwriteContentToFile] - Error removing file: %s , error is %s", targetFile, err.Error())
	}

	return BasicAppendContentToFile(content, targetFile)
}

// 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
}
