package gallery

import (
	"context"
	"math"

	"github.com/InfinityTools/go-binpack2d"
)

type Gallery struct {
	GridWith   int
	GridHeight int
	Images     []Image
}
type Set struct {
	SM  Gallery
	LG  Gallery
	XLG Gallery
}

func (s *Service) GetGallerySet(ctx context.Context) (gallerySet Set, err error) {
	gallerySet.SM, err = s.GetGallery(ctx, 50)
	if err != nil {
		return
	}
	gallerySet.LG, err = s.GetGallery(ctx, 80)
	if err != nil {
		return
	}

	gallerySet.XLG, err = s.GetGallery(ctx, 120)
	if err != nil {
		return
	}

	return
}

func (s *Service) GetGallery(ctx context.Context, width int) (gallery Gallery, err error) {
	imgs, err := s.GetImages(ctx)
	if err != nil {
		return
	}

	packer := binpack2d.Create(width, 999999)

	for len(imgs) > 0 {
		unused := make([]Image, 0, len(imgs))
		for _, img := range imgs {
			adjustImageSize(&img, 200)
			rect, ok := packer.Insert(img.Width, img.Height, binpack2d.RULE_BEST_SHORT_SIDE_FIT)
			if !ok {
				unused = append(unused, img)
				continue
			}

			img.X = rect.X
			img.Y = rect.Y

			gallery.Images = append(gallery.Images, img)
		}
		imgs = unused
	}

	packer.ShrinkBin(false)

	gallery.GridHeight = packer.GetHeight()
	gallery.GridWith = packer.GetWidth()

	return
}

// adjustImageSize adjusts the image size so that the aspect ratio stays the same
// but the image area is the given parameter.
func adjustImageSize(img *Image, area int) {
	// Calculate the original aspect ratio (W / H)
	aspectRatio := float64(img.Width) / float64(img.Height)

	// Calculate new height and width using the derived formulas
	newHeight := math.Sqrt(float64(area) / aspectRatio)
	newWidth := newHeight * aspectRatio

	// Round to the nearest integer to minimize precision loss
	img.Width = int(math.Round(newWidth))
	img.Height = int(math.Round(newHeight))
}
