package main

import (
	"bufio"
	"fmt"
	"image"
	"io/fs"
	"os"
	"slices"
	"strings"
	"sync"

	"fyne.io/fyne/v2/data/binding"
	"github.com/disintegration/imaging"
	"github.com/pixiv/go-libwebp/webp"
	"github.com/rwcarlsen/goexif/tiff"
	"golang.org/x/image/draw"
)

func convertRange(inputPath, outputPath string, files []fs.DirEntry, threads, mod int, progress binding.Float, unconverted binding.StringList, wg *sync.WaitGroup) {
	defer wg.Done()

	for i, file := range files {
		if i%threads == mod {
			if err := convert(inputPath, outputPath, file); err != nil {
				unconverted.Append(file.Name())
			}

			p, _ := progress.Get()
			progress.Set((p*float64(len(files)) + 1) / float64(len(files)))
		}
	}
}

func convert(inputPath, outputPath string, file fs.DirEntry) error {
	name := file.Name()
	parts := strings.Split(name, ".")
	ext := strings.ToLower(parts[len(parts)-1])
	if !file.Type().IsRegular() || !slices.Contains(supported, ext) {
		return fmt.Errorf("file type  %s is not supported", ext)
	}

	img, orientation, err := ReadIMG(fmt.Sprintf("%s/%s", inputPath, name))
	if err != nil {
		return err
	}

	dest, err := rotate(scale(img), orientation)
	if err != nil {
		return err
	}

	io, err := os.Create(fmt.Sprintf("%s/%swebp", outputPath, strings.TrimSuffix(name, ext)))
	if err != nil {
		return err
	}

	wr := bufio.NewWriter(io)
	defer func() {
		wr.Flush()
		io.Close()
	}()

	config, err := webp.ConfigPreset(webp.PresetDefault, 75)
	if err != nil {
		return err
	}
	config.SetAlphaQuality(100)
	config.SetMethod(4)
	config.SetSegments(4)
	config.SetSNSStrength(50)
	config.SetFilterStrength(60)
	config.SetFilterSharpness(0)

	err = webp.EncodeRGBA(wr, dest, config)
	if err != nil {
		return err
	}

	return nil
}

func scale(img image.Image) (dest *image.NRGBA) {
	b := img.Bounds()
	factor := float32(b.Max.X) / float32(b.Max.Y)
	dest = image.NewNRGBA(image.Rect(0, 0, int(factor*1440), 1440))
	draw.ApproxBiLinear.Scale(dest, dest.Rect, img, b, draw.Over, nil)
	return dest
}

func rotate(img image.Image, orientation *tiff.Tag) (dest *image.NRGBA, err error) {
	rotate, err := orientation.Int(0)
	if err != nil {
		return nil, err
	}
	switch rotate {
	case 3:
		dest = imaging.Rotate180(img)
	case 6:
		dest = imaging.Rotate270(img)
	case 8:
		dest = imaging.Rotate90(img)
	}

	return dest, nil
}