package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"log/slog"
	"net/http"
	"os"
	"time"

	"anime.bike/slogutil/slogenv"
	"anime.bike/stint"
	"git.tuxpa.in/a/nori/renderer"

	"git.tuxpa.in/a/nori"
	"git.tuxpa.in/a/nori/utils"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

var (
	servePtr  = flag.Bool("serve", false, "launch web server")
	dumpPtr   = flag.Bool("d", false, "dump nri file to zip")
	silentPtr = flag.Bool("s", false, "silent")
	filePtr   = flag.String("f", "example.nri", "file to load")
	outputPtr = flag.String("o", "output.zip", "output zip file")
)

func init() {
	slog.SetDefault(slog.New(stint.NewHandler(os.Stderr, &stint.Options{
		AddSource: true,
		Level:     slogenv.EnvLevel(),
	})))
}

func main() {
	flag.Parse()
	if *servePtr {
		serve()
		return
	}
	if *dumpPtr {
		filename := *filePtr
		output := *outputPtr
		if _, err := os.Stat(filename); err != nil {
			printIf("could not find file %s\n", filename)
			return
		}
		err := dump(filename, output)
		if err != nil {
			fmt.Println(err)
			return
		}
		return
	}
	flag.PrintDefaults()
}

func printIf(s string, args ...interface{}) {
	if !*silentPtr {
		fmt.Printf(s, args...)
	}
}

func dump(filename string, output string) error {
	start := time.Now()
	printIf("reading file '%s'\n", filename)
	n, err := nori.FromFile(filename)
	if err != nil {
		return fmt.Errorf("decode: %w", err)
	}
	out := new(bytes.Buffer)
	printIf("rendering %d animation(s)\n", n.AnimationCount)
	animations, err := renderer.RenderAnimationsApng(n)
	if err != nil {
		return fmt.Errorf("animation: %w", err)
	}
	printIf("saving to %s \n", output)
	if err := utils.ZipApngs(out, animations); err != nil {
		return fmt.Errorf("zipping: %w", err)
	}
	printIf("done in %v \n", time.Now().Sub(start))
	os.WriteFile(output, out.Bytes(), 0740)
	return nil
}

func serve() {
	r := chi.NewRouter()

	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)

	r.Use(middleware.Timeout(60 * time.Second))

	r.Post("/animations", func(w http.ResponseWriter, r *http.Request) {
		output_type := r.URL.Query().Get("format")
		switch output_type {
		case "":
			output_type = "apng"
		case "apng":
		default:
			http.Error(w, "output type not supported", 500)
			return
		}
		n := nori.New()
		if err := n.Decode(r.Body); err != nil {
			http.Error(w, err.Error(), 500)
		}
		frames, err := renderer.RenderAnimationsApng(n)
		if err != nil {
			http.Error(w, err.Error(), 500)
		}
		if err := utils.ZipApngs(w, frames); err != nil {
			http.Error(w, err.Error(), 500)
		}
		w.WriteHeader(200)
	})

	log.Println("listening on 3333")
	http.ListenAndServe(":3333", r)
}
