package utils

import (
	"archive/zip"
	"fmt"
	"io"
	"io/fs"
	"os"
	"path/filepath"
	"strings"
)

func Zip(zipPath string, paths ...string) error {
	// Create zip file and it's parent dir.
	if err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil {
		return err
	}
	archive, err := os.Create(zipPath)
	if err != nil {
		return err
	}
	defer archive.Close()

	// New zip writer.
	zipWriter := zip.NewWriter(archive)
	defer zipWriter.Close()

	// Traverse the file or directory.
	for _, rootPath := range paths {
		// Remove the trailing path separator if path is a directory.
		rootPath = strings.TrimSuffix(rootPath, string(os.PathSeparator))

		// Visit all the files or directories in the tree.
		err = filepath.Walk(rootPath, walkFunc(rootPath, zipWriter))
		if err != nil {
			return err
		}
	}
	return nil
}

func walkFunc(rootPath string, zipWriter *zip.Writer) filepath.WalkFunc {
	return func(path string, info fs.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// If a file is a symbolic link it will be skipped.
		if info.Mode()&os.ModeSymlink != 0 {
			return nil
		}

		// Create a local file header.
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		// Set compression method.
		header.Method = zip.Deflate

		// Set relative path of a file as the header name.
		header.Name, err = filepath.Rel(rootPath, path)
		fmt.Println("--------------------------------------------------------")
		fmt.Println(rootPath)
		if err != nil {
			return err
		}
		if info.IsDir() {
			// header.Name += string(os.PathSeparator)
			header.Name += string(os.PathSeparator)
			fmt.Println(header.Name)
		}

		// Create writer for the file header and save content of the file.
		headerWriter, err := zipWriter.CreateHeader(header)
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		fmt.Println(path)
		fmt.Println(header.Name)
		f, err := os.Open(path)
		if err != nil {
			return err
		}
		defer f.Close()
		_, err = io.Copy(headerWriter, f)
		return err
	}
}

func ZipFile(srcFile, destFile string) error {
	// 创建目标文件，即zip文件
	zipFile, err := os.Create(destFile)
	if err != nil {
		return err
	}
	defer zipFile.Close()
	// 创建writer，准备向目标文件中写入数据
	writer := zip.NewWriter(zipFile)
	defer writer.Close()

	// 遍历文件（如果srcFile是个目录的话）
	err = filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error {
		// 遍历发生错误，退出
		if err != nil {
			return err
		}

		// 创建zip文件信息头
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		header.Name = path
		if info.IsDir() {
			header.Name += "\\"
		} else {
			header.Method = zip.Deflate
		}

		// 将信息头写入到writer中
		writer, err := writer.CreateHeader(header)
		if err != nil {
			return err
		}

		// 如果是目录，直接写个头就可以了，filepath.Walk会继续遍历目录
		if info.IsDir() {
			return nil
		}

		// 如果是文件，则将文件内容写入到writer中
		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()
		_, err = io.Copy(writer, file)

		return err
	})

	return err
}
