package webpconverter

import (
	"bytes"
	"image"
	"image/png"
	"io"
	"path/filepath"
	"strings"

	"github.com/chai2010/webp"
	"github.com/pocketbase/pocketbase"
	"github.com/pocketbase/pocketbase/core"
	"github.com/pocketbase/pocketbase/tools/filesystem"
	"github.com/pocketbase/pocketbase/tools/hook"
)

func CreateEventHandler(app *pocketbase.PocketBase) *hook.Handler[*core.RecordEvent] {
	return &hook.Handler[*core.RecordEvent]{
		Func: func(e *core.RecordEvent) error {
			fieldsData := e.Record.FieldsData()
			for _, v := range fieldsData {
				if files, ok := v.([]interface{}); ok {
					for _, f := range files {
						if file, ok := f.(*filesystem.File); ok {
							if shouldBeReplacedWithWebp(file.Name) {
								convertToWebp(file)
							}
						}
					}
				}
				if f, ok := v.(interface{}); ok {
					if file, ok := f.(*filesystem.File); ok {
						if shouldBeReplacedWithWebp(file.Name) {
							convertToWebp(file)
						}
					}
				}
			}
			return e.Next()
		},
		Priority: 100,
	}
}

func ThumbEventHandler(app *pocketbase.PocketBase) *hook.Handler[*core.FileDownloadRequestEvent] {
	return &hook.Handler[*core.FileDownloadRequestEvent]{
		Func: func(fdre *core.FileDownloadRequestEvent) error {
			if filepath.Ext(fdre.ServedName) == ".webp" {

				filename := fdre.Request.PathValue("filename")
				baseFilesPath := fdre.Record.BaseFilesPath()

				fs, err := app.App.NewFilesystem()
				if err != nil {
					return err
				}
				defer fs.Close()

				blob, err := fs.GetReader(baseFilesPath + "/thumbs_" + filename + "/" + fdre.ServedName)
				if err != nil {
					blob, err = fs.GetReader(baseFilesPath + "/" + fdre.ServedName)
					if err != nil {
						return err
					}
				}
				defer blob.Close()

				img, err := png.Decode(blob)
				if err != nil {
					return fdre.Next()
				}

				buf := bytes.Buffer{}
				err = webp.Encode(&buf, img, &webp.Options{Quality: 80})
				if err != nil {
					return err
				}
				err = fs.Upload(buf.Bytes(), baseFilesPath+"/thumbs_"+filename+"/"+fdre.ServedName)
				if err != nil {
					_, err := fdre.Response.Write(buf.Bytes())
					if err != nil {
						return err
					}
					return nil
				}
				return fdre.Next()
			}
			return fdre.Next()
		},
		Priority: 99,
	}
}

func convertToWebp(file *filesystem.File) error {
	file.Name = replaceExtWithWebp(file.Name)
	file.OriginalName = replaceExtWithWebp(file.OriginalName)
	ff, err := file.Reader.Open()
	if err != nil {
		return err
	}
	defer ff.Close()
	fff, err := io.ReadAll(ff)
	if err != nil {
		return err
	}
	img, _, err := image.Decode(bytes.NewReader(fff))
	if err != nil {
		return err
	}

	buf := bytes.Buffer{}
	err = webp.Encode(&buf, img, &webp.Options{Quality: 80})
	if err != nil {
		return err
	}
	file.Reader = &memFileReader{data: buf.Bytes()}
	file.Size = int64(buf.Len())
	return nil
}

func replaceExtWithWebp(path string) string {
	// List of image extensions to convert
	exts := []string{".png", ".jpg", ".jpeg", ".bmp", ".tiff"}

	for _, ext := range exts {
		if strings.HasSuffix(strings.ToLower(path), ext) {
			return strings.TrimSuffix(path, ext) + ".webp"
		}
	}
	return path
}

func shouldBeReplacedWithWebp(path string) bool {
	// List of image extensions to convert
	exts := []string{".png", ".jpg", ".jpeg", ".bmp", ".tiff"}

	for _, ext := range exts {
		if strings.HasSuffix(strings.ToLower(path), ext) {
			return true
		}
	}
	return false
}
