// Copyright 2023 wanderer <a_mirre at utb dot cz>
// SPDX-License-Identifier: GPL-3.0-or-later

package report

import (
	_ "embed"
	"log"
	"os"
	"sort"
	"text/template"
	"time"

	"git.dotya.ml/wanderer/math-optim/util"
)

// Pic holds path to pic along with its caption.
// Bench field is set optionally (e.g. in case of the pic depicting
// comparison of means).
type Pic struct {
	Caption  string
	FilePath string
	Bench    string // optionally set.
}

type PlotPics []Pic

// PicList is a structure holding a slice of pics and {bench,algo} metadata.
type PicList struct {
	Algo  string
	Bench string
	Pics  PlotPics
}

//go:embed pics.tmpl
var tmplPicsFile []byte

// Len implements the sort.Interface.
func (p PlotPics) Len() int {
	return len(p)
}

// Less implements the sort.Interface.
// note: sorting based on filename
func (p PlotPics) Less(i, j int) bool {
	return p[i].FilePath < p[j].FilePath
}

// Swap implements the sort.Interface.
func (p PlotPics) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

// NewPic returns a new copy of Pic.
func NewPic() *Pic {
	return &Pic{}
}

// NewPicList returns a new copy of PicList.
func NewPicList() *PicList {
	return &PicList{}
}

// SavePicsToFile saves each pic list for all bench funcs of a specified algo
// to a file.
func SavePicsToFile(pls, plsMean []PicList, algoName string) {
	paths := make([]string, 0, len(pls))

	ptf := picTexFiles{Algo: algoName}

	for i, p := range pls {
		safeName := util.SanitiseFName(p.Algo + "-" + p.Bench)
		texPicsFile := GetTexDir() + "pics-" + safeName + ".tex"
		tmplPics := template.New("pics")

		tmplPics = template.Must(tmplPics.Parse(string(tmplPicsFile)))

		paths = append(paths, texPicsFile)
		// keep the slice sorted.
		sort.Strings(paths)

		// make sure the output dir exists, else die early.
		if err := util.CreatePath(GetTexDir()); err != nil {
			log.Fatalln(err)
		}

		f, err := os.Create(texPicsFile)
		if err != nil {
			log.Println(err)
		}
		defer f.Close()

		err = tmplPics.Execute(f, struct {
			Algo      string
			Bench     string
			Pics      []Pic
			PicsMean  []Pic
			Timestamp time.Time
		}{
			Algo:      p.Algo,
			Bench:     p.Bench,
			Pics:      p.Pics,
			PicsMean:  plsMean[i].Pics,
			Timestamp: time.Now(),
		})

		if err != nil {
			log.Println(err)
		}
	}

	ptf.FilePaths = paths
	allPics.TexFiles = append(allPics.TexFiles, ptf)
}
