package blur

import (
	"errors"
	"fmt"
	"github.com/disintegration/imaging"
	"github.com/pdfcpu/pdfcpu/pkg/api"
	"io/fs"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"time"
)

const (
	SIGMA      = 5
	BlurPrefix = "blur-"
)

var (
	outPath = "./static/"
	cmdPath = "./cmd/pdftopng.exe" //xpdf https://www.xpdfreader.com/download.html
	tmpPath = "./tmp/"
)

// InitConfig 初始化配置
// cp 执行文件目录
// op 输出目录
// tp 临时文件目录
func InitConfig(cp, op, tp string) {
	cmdPath = cp
	outPath = op
	tmpPath = tp
	initConfig()
}

func InitDefaultConfig() {
	initConfig()
}

func initConfig() {
	if _, err := os.Stat(tmpPath); err != nil {
		if errors.Is(err, os.ErrNotExist) {
			os.MkdirAll(tmpPath, os.ModePerm)
		}
	}
	if _, err := os.Stat(outPath); err != nil {
		if errors.Is(err, os.ErrNotExist) {
			os.MkdirAll(outPath, os.ModePerm)
		}
	}
	if runtime.GOOS == "linux" {
		cmdPath = strings.TrimRight(cmdPath, ".exe")
	}
}

// CheckFileExist  检查文件是否存在
func CheckFileExist(p string) (string, error) {
	filename := filepath.Base(p)
	f, err := os.Stat(filepath.Join(outPath, filename))
	if f != nil && err == nil {
		return p, nil
	}
	return "", fmt.Errorf("file not exisit %v", p)
}

// FileBlur 文件模糊处理
// blurFlag true:执行模糊 false:不需要模糊
func FileBlur(filePath string, blurFlag bool) (string, error) {
	filename := filepath.Base(filePath)
	// 判断文件是否存在
	if !blurFlag {
		return filePath, nil
	}
	if fs, e := CheckFileExist(filepath.Join(outPath, BlurPrefix+filename)); e == nil && len(fs) > 0 {
		return fs, nil
	}
	var err error
	filePath, err = ResolveFilePath(filePath)
	if err != nil {
		return "", err
	}
	ext := filepath.Ext(filePath)
	ext = strings.TrimSpace(ext)
	if ext == ".pdf" {
		return PDFBlur(filePath)
	}
	if strings.Contains(".png|.jpg|.jpeg", ext) {
		return ImageBlur(filePath)
	}
	return filePath, nil
}

// ImageBlur 图片模糊处理
func ImageBlur(filePath string) (string, error) {
	filename := filepath.Base(filePath)
	blurFilename := filepath.Join(outPath, BlurPrefix+filename)

	img, err := imaging.Open(filePath)
	if err != nil {
		return "", err
	}
	dst := imaging.Blur(img, SIGMA)
	err = imaging.Save(dst, blurFilename)
	// clear
	os.Remove(filePath)
	return blurFilename, err
}

// PDFBlur PDF 模糊处理
func PDFBlur(pdfPath string) (string, error) {
	rand.Seed(time.Now().UnixNano())
	filename := filepath.Base(pdfPath)
	blurFilename := filepath.Join(outPath, BlurPrefix+filename)
	tmpblurFilename := filepath.Join(outPath, BlurPrefix+fmt.Sprintf("%v-", rand.Int())+filename)
	tmpImagePath, err := ioutil.TempDir("", "image-")
	tmpImagePathBlur, err := ioutil.TempDir("", "image-"+BlurPrefix)
	cmd := exec.Command(cmdPath, pdfPath, tmpImagePath+"/")
	err = cmd.Run()
	if err != nil {
		return "", err
	}

	var blurFiles = make([]string, 0)
	files, _ := ioutil.ReadDir(tmpImagePath)
	for _, f := range files {
		img, _ := imaging.Open(filepath.Join(tmpImagePath, f.Name()))
		dst := imaging.Blur(img, SIGMA)
		blurFiles = append(blurFiles, filepath.Join(tmpImagePathBlur, f.Name()))
		_ = imaging.Save(dst, filepath.Join(tmpImagePathBlur, f.Name()))
	}
	sort.Strings(blurFiles)
	err = api.ImportImagesFile(blurFiles, tmpblurFilename, nil, nil)
	if err != nil {
		return "", err
	}
	if err = os.Rename(tmpblurFilename, blurFilename); err != nil {
		return "", nil
	}
	//clear
	os.RemoveAll(tmpImagePath)
	os.RemoveAll(tmpImagePathBlur)
	os.Remove(pdfPath)
	return blurFilename, nil
}

// ResolveFilePath 解析文件
func ResolveFilePath(filePath string) (string, error) {
	if strings.HasPrefix(filePath, "http") || strings.HasPrefix(filePath, "https") {
		return download(filePath)
	}
	return filePath, nil
}

func download(url string) (string, error) {
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	fileName := filepath.Base(url)
	data, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	tmpFilePath := filepath.Join(tmpPath, fileName)
	err = ioutil.WriteFile(tmpFilePath, data, fs.ModePerm)
	if err != nil {
		return "", nil
	}
	return tmpFilePath, err
}