package httpd

import (
    "fmt"
    "github.com/jumpserver/koko/pkg/logger"
    "io"
    "os"
    "path/filepath"
    "strings"
    "sync"
    "time"
)

// filepath: /data/file/日期/download or upload/filename
var baseDir = "/data/file"

// chunk upload
var chunkUploadMap = make(map[string]string)

var chunkLock = new(sync.Mutex)

func downloadToLocal(filename string, reader io.Reader) error {
    logger.Info("download:", "filename:", filename)
    dir := getDir("download")
    realPath := filepath.Join(dir, getFilename(filename))
    writer, err := os.OpenFile(realPath, os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
        logger.Error("[download] path: ", realPath, " create failed, error:", err)
        return err
    }
    defer writer.Close()
    _, err = io.Copy(writer, reader)
    if err != nil {
        logger.Error("[download] path: ", realPath, " save failed, error:", err)
        return err
    }
    logger.Info("[download] path: ", realPath, " local save success")
    return nil
}

func uploadToLocal(filename string, reader io.Reader) error {
    logger.Error("upload: hostname:", ";filename:", filename)
    dir := getDir("upload")
    realPath := filepath.Join(dir, getFilename(filename))
    writer, err := os.OpenFile(realPath, os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
        logger.Error("[upload] path: ", realPath, " create failed, error:", err)
        return err
    }
    defer writer.Close()
    _, err = io.Copy(writer, reader)
    if err != nil {
        logger.Error("[upload] path: ", realPath, " save failed, error:", err)
        return err
    }
    logger.Error("[upload] path: ", realPath, " local save success")
    return nil
}

func chunkUploadToLocal(uuid string, cid int, filename string, reader io.Reader) error {
    key := getChunkKey(uuid, cid)
    chunkLock.Lock()
    realPath, ok := chunkUploadMap[key]
    chunkLock.Unlock()
    if !ok {
        dir := getDir("upload")
        realPath = filepath.Join(dir, getFilename(filename))
        chunkLock.Lock()
        chunkUploadMap[key] = realPath
        chunkLock.Unlock()
    }
    writer, err := os.OpenFile(realPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        logger.Error("[download] path: ", realPath, " create failed, error:", err)
        return err
    }
    defer writer.Close()

    _, err = io.Copy(writer, reader)
    if err != nil {
        logger.Error("[chunkUpload] path: ", realPath, " save failed, error:", err)
        return err
    }
    return nil
}

func chunkMergeToLocal(uuid string, cid int) error {
    key := getChunkKey(uuid, cid)
    chunkLock.Lock()
    if _, ok := chunkUploadMap[key]; ok {
        delete(chunkUploadMap, key)
    }
    chunkLock.Unlock()
    return nil
}


func makeDir(path string) {
    _, err := os.Stat(path)
    if err != nil {
        if os.IsNotExist(err) {
            os.MkdirAll(path, os.ModePerm)
        }
    }
}

func getDir(direction string) string {
    dir := filepath.Join(baseDir, time.Now().Format("2006-01-02"), direction)
    makeDir(dir)
    return dir
}

func getFilename(filename string) string {
    filename = strings.TrimPrefix(filename, "/")
    filename = strings.ReplaceAll(filename, "/", "-")
    filename = filename + "." + time.Now().Format("20060102150405")
    return filename
}

func getChunkKey(uuid string, cid int) string {
    return fmt.Sprintf("%s-%d", uuid, cid)
}