package handler

import (
	"errors"
	"fmt"
	"io/fs"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"git.pyer.club/kingecg/gologger"
)

type FileHandler struct {
	WPath   string
	Root    string
	Default string
	http.FileSystem
}

func (f FileHandler) String() string {
	return fmt.Sprintf("FileHandler:{WPath:%s,Root:%s,Default:%s}", f.WPath, f.Root, f.Default)
}
func (f FileHandler) Open(name string) (http.File, error) {
	l := gologger.GetLogger("filehandler")
	l.Debug("access:", name)
	if strings.HasPrefix(name, "../") {
		return nil, errors.New("not permitted")
	}
	relatedPath := strings.TrimPrefix(name, f.WPath)

	rPath := filepath.Join(f.Root, strings.TrimPrefix(relatedPath, "/"))
	l.Debug("access:", rPath)
	// if rPath == f.Root {
	// 	if f.Default == "" {
	// 		return nil, errors.New("not permit list dir")
	// 	}
	// 	rPath = filepath.Join(rPath, f.Default)
	// }

	fInfo, _, err := FileExists(rPath)
	if err != nil {
		l.Error("access file error:", rPath, err)
		return nil, err
	}

	if fInfo.IsDir() && rPath != strings.TrimSuffix(f.Root, "/") {
		return nil, errors.New("not permit list dir")
	}

	if fInfo.Mode() == fs.ModeSymlink {
		return nil, errors.New("not permit follow symbol link")
	}

	fp, err := os.Open(rPath)
	if err != nil {
		l.Error("open file fail", err)
		return nil, err
	}
	return fp, nil
}

func FileExists(name string) (os.FileInfo, bool, error) {
	info, err := os.Stat(name)
	if err != nil {
		return nil, os.IsExist(err), err
	}
	return info, true, nil
}

func NewFileHandler(f FileHandler) http.Handler {
	return http.FileServer(f)
}

func init() {
	mime.AddExtensionType(".js", "application/javascript")
	mime.AddExtensionType(".css", "text/css")
	mime.AddExtensionType(".html", "text/html")
	mime.AddExtensionType(".htm", "text/html")
	mime.AddExtensionType(".svg", "image/svg+xml")
	mime.AddExtensionType(".png", "image/png")
	mime.AddExtensionType(".mjs", "application/javascript")
}
