package file_cache

import (
	"bufio"
	"fmt"
	"github.com/robfig/cron"
	"github.com/vrg0/go-common/logger"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	WRITING = ".writing"
	DELETE  = ".delete"
	CACHE   = ".cache"
)

type fileHolder struct {
	fileName string
	path     string
	file     *os.File
	fileSize fileSize
}

type fileSize struct {
	size int
	lock sync.Mutex
}

func (fs *fileSize) Get() int {
	return fs.size
}
func (fs *fileSize) Add(offset int) {
	fs.lock.Lock()
	defer fs.lock.Unlock()

	fs.size = fs.size + offset
	if fs.size < 0 {
		fs.size = 0
		return
	}

}

var currentFile *fileHolder
var fileCacheOnce sync.Once

func Load(path string) {
	if path == "" {
		path = "../"
	}
	if !strings.HasSuffix(path, "/") {
		path = path + "/"
	}
	if !pathExists(path) {
		mkdir(path)
	}
	currentFile = &fileHolder{}
	currentFile.path = path
	go func() {
		fileCacheOnce.Do(func() {
			mark()   //将因为服务停止导致未及时更改状态的文件修改为缓存状态
			Delete() //删除过期文件
			pickup() //统计上次未提交的缓存文件的数量
		})
	}()
}

func create() {
	current := time.Now().Unix()
	currentFile.fileName = currentFile.path + strconv.FormatInt(current, 10)
	file, err := os.Create(currentFile.fileName + WRITING)
	if err != nil {
		logger.Error("创建缓存文件失败", err)
	}
	logger.Info("打开缓存文件", currentFile.fileName)
	currentFile.file = file
	currentFile.fileSize.Add(1)
	logger.Info("文件缓存数：", currentFile.fileSize.Get())
}

func closed() {
	defer os.Rename(currentFile.fileName+WRITING, currentFile.fileName+CACHE)
	logger.Info("关闭缓存文件")
	currentFile.file.Close()
}

func Delete() {
	fileNames := scan(DELETE)
	for _, name := range fileNames {
		os.Remove(currentFile.path + name)
		logger.Info("删除缓存文件", name)
	}
}

func pickup() {
	logger.Info("获取缓存文件数量")
	files := scan(CACHE)
	currentFile.fileSize.Add(len(files))
}

func mark() {
	fileName := scan(WRITING)
	logger.Info("重新标记缓存文件")
	for _, name := range fileName {
		os.Rename(currentFile.path+name, currentFile.path+strings.Split(name, ".")[0]+CACHE)
	}
}

func Recover(submit func(data []string) error) {
	if currentFile.fileSize.Get() <= 0 {
		return
	}
	fileNames := scan(CACHE)
	for _, name := range fileNames {
		err := submit(Read(currentFile.path + name))
		if err != nil {
			logger.Error("重新提交缓存异常：", err)
			return
		}
		os.Rename(currentFile.path+name, currentFile.path+strings.Split(name, ".")[0]+DELETE)
		currentFile.fileSize.Add(-1)
		logger.Info("文件缓存数：", currentFile.fileSize.Get())
	}
	go Delete()
}

func Write(data string) error {
	writer := bufio.NewWriter(currentFile.file)
	_, err := writer.WriteString(data + "\n")
	if err != nil {
		return err
	}
	go writer.Flush()
	return nil
}

func scan(suffix string) []string {
	files, _ := ioutil.ReadDir(currentFile.path)
	fileNames := make([]string, 0)
	for _, f := range files {
		if strings.HasSuffix(f.Name(), suffix) {
			fileNames = append(fileNames, f.Name())
		}
	}
	return fileNames
}

func Read(fileName string) []string {
	file, err := os.Open(fileName)
	if err != nil {
		logger.Error("未找到对应的文件：", err)
	}
	reader := bufio.NewReader(file)
	data := make([]string, 0)
	for {
		line, _, err := reader.ReadLine()
		if err == io.EOF {
			break
		}
		data = append(data, string(line))
	}
	return data
}

func pathExists(path string) bool {

	_, err := os.Stat(path)

	if err == nil {
		return true
	}

	return !os.IsNotExist(err)
}

func mkdir(path string) bool {
	err := os.Mkdir(path, os.ModePerm)
	return err == nil
}

func RegisterJob(submit func(data []string) error) {
	c := cron.New()
	err := c.AddFunc("@every 1m", func() {
		if !Enabled() {
			logger.Info("开始扫描缓存文件")
			Recover(submit)
		}
	})
	if err != nil {
		fmt.Print("err")
	}

	c.Start()
}
