package contented

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net/http"
	"path/filepath"

	"code.ivysaur.me/thumbnail"
)

func getThumbnailerConfig(t byte) (*thumbnail.Config, error) {
	// Modelled on what imgur.com offers
	// @ref https://api.imgur.com/models/image#thumbs

	opts := thumbnail.Config{
		Aspect: thumbnail.FitOutside,
		Output: thumbnail.Jpeg,
		Scale:  thumbnail.Bicubic,
	}

	switch t {
	case 's':
		opts.Width = 90
		opts.Height = 90
	case 'b':
		opts.Width = 160
		opts.Height = 160
	case 't':
		opts.Width = 160
		opts.Height = 160
		// thumbnail.ASPECT_RESPECT_MAX_DIMENSION_ONLY
	case 'm':
		opts.Width = 340
		opts.Height = 340
		// thumbnail.ASPECT_RESPECT_MAX_DIMENSION_ONLY
	case 'l':
		opts.Width = 640
		opts.Height = 640
		// thumbnail.ASPECT_RESPECT_MAX_DIMENSION_ONLY
	case 'h':
		opts.Width = 1024
		opts.Height = 1024
		// thumbnail.ASPECT_RESPECT_MAX_DIMENSION_ONLY
	default:
		return nil, errors.New("Unsupported thumbnail type (should be s/b/t/m/l/h)")
	}

	return &opts, nil
}

func (this *Server) handleThumb(w http.ResponseWriter, r *http.Request, thumbnailType byte, fileId string) {
	ctx := r.Context()

	opts, err := getThumbnailerConfig(thumbnailType)
	if err != nil {
		log.Printf("%s Thumbnail failed: %s\n", this.remoteIP(r), err.Error())
		http.Error(w, err.Error(), 400)
		return
	}

	// Only a limited number of thumbnails can be generated concurrently
	<-this.thumbnailSem
	defer func() { this.thumbnailSem <- struct{}{} }()

	if ctx.Err() != nil {
		// The request was already cancelled
		return
	}

	t := thumbnail.NewThumbnailerEx(opts)

	err = this.handleThumbInternal(ctx, w, t, fileId)
	if err != nil {
		log.Printf("%s Thumbnail failed: %s\n", this.remoteIP(r), err.Error())

		w.Header().Set(`Location`, fmt.Sprintf(`/nothumb_%d.png`, opts.Height))
		w.WriteHeader(302)
	}
}

func (this *Server) handleThumbInternal(ctx context.Context, w http.ResponseWriter, t thumbnail.Thumbnailer, fileId string) error {

	// Load metadata
	m, err := this.Metadata(fileId)
	if err != nil {
		return err
	}

	filePath := filepath.Join(this.opts.DataDirectory, m.FileHash)
	thumb, err := t.RenderFileAs(filePath, m.MimeType)
	if err != nil {
		return err
	}

	w.Header().Set(`Content-Length`, fmt.Sprintf("%d", len(thumb)))
	w.Header().Set(`Content-Type`, `image/jpeg`)
	w.WriteHeader(200)
	w.Write(thumb)

	return nil
}
