package helpers

import (
	"embed"
	"fmt"
	"io"
	"io/fs"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/gin-contrib/static"
	"github.com/gin-gonic/gin"
)

func SetCorsAndNoCacheHeaders() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	}
}

type embedFileSystem struct {
	http.FileSystem
	indexes bool
}

func (e embedFileSystem) Exists(_ string, path string) bool {
	f, err := e.Open(path)
	if err != nil {
		return false
	}

	// check if indexing is allowed
	s, _ := f.Stat()
	if s.IsDir() && !e.indexes {
		return false
	}

	return true
}

func EmbedFolder(fsEmbed embed.FS, targetPath string, index bool) static.ServeFileSystem {
	subFS, err := fs.Sub(fsEmbed, targetPath)
	if err != nil {
		panic(err)
	}
	return embedFileSystem{
		FileSystem: http.FS(subFS),
		indexes:    index,
	}
}

func SendSong(ctx *gin.Context, Filename string) {
	fmt.Println("Client requests: " + Filename)

	//Check if file exists and open
	openFile, err := os.Open(Filename)
	if err != nil {
		//File not found, send 404
		http.Error(ctx.Writer, "Song not found.", 404)
		return
	}
	defer func(openFile *os.File) {
		_ = openFile.Close()
	}(openFile) //Close after function return

	//File is found, create and send the correct headers

	//Get the Content-Type of the file
	//Create a buffer to store the header of the file in
	FileHeader := make([]byte, 512)
	//Copy the headers into the FileHeader buffer
	_, _ = openFile.Read(FileHeader)
	//Get content type of file
	//FileContentType := http.DetectContentType(FileHeader)

	//Get the file size
	FileStat, _ := openFile.Stat()                     //Get info from file
	FileSize := strconv.FormatInt(FileStat.Size(), 10) //Get file size as a string

	//Send the headers
	//writer.Header().Set("Content-Disposition", "attachment; filename="+Filename)
	ctx.Writer.Header().Set("Content-Type", "audio/mpeg")
	ctx.Writer.Header().Set("Content-Length", FileSize)
	ctx.Writer.Header().Set("Expires", "Tue, 03 Jul 2001 06:00:00 GMT")
	ctx.Writer.Header().Set("Last-Modified", time.Now().String()+" GMT")
	ctx.Writer.Header().Set("Cache-Control", "no-cache, no-store, private, max-age=0")
	ctx.Writer.Header().Set("Pragma", "no-cache")
	ctx.Writer.Header().Set("X-Accel-Expires", "0")

	var etagHeaders = []string{
		"ETag",
		"If-Modified-Since",
		"If-Match",
		"If-None-Match",
		"If-Range",
		"If-Unmodified-Since",
	}

	for _, v := range etagHeaders {
		if ctx.Request.Header.Get(v) != "" {
			ctx.Request.Header.Del(v)
		}
	}

	//Send the file
	//We read 512 bytes from the file already, so we reset the offset back to 0
	_, _ = openFile.Seek(0, 0)
	_, _ = io.Copy(ctx.Writer, openFile) //'Copy' the file to the client
	return
}
