package main

import (
	"context"
	"embed"
	_ "embed"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"path"
	"slices"
	"strings"
	"syscall"

	"ffmpeg.d/pkg/fs"
)

//go:embed *.tmpl
var TMPL embed.FS

func main() {
	ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT)
	defer can()

	if err := Run(ctx, os.Args[1:]); err != nil {
		panic(err)
	}
}

func Run(ctx context.Context, args []string) error {
	flags := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
	d := flags.String("d", "./testdata/", "directory containing directories of (x.jpg,x.mp4)")
	p := flags.Int("p", 38080, "port to listen on")
	if err := flags.Parse(args); err != nil {
		return err
	}

	tmpl, err := template.ParseFS(TMPL, "*.tmpl")
	if err != nil {
		return err
	}

	s := &http.Server{
		Addr: fmt.Sprintf(":%d", *p),
		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if strings.HasPrefix(r.URL.Path, "/media/") {
				http.StripPrefix("/media/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					http.FileServer(http.Dir(*d)).ServeHTTP(w, r)
				})).ServeHTTP(w, r)
				return
			}

			type Series struct {
				HREF      string
				Thumbnail string
			}

			ds, err := fs.LsD(*d)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			seriesByKey := map[string]Series{}
			for _, d := range ds {
				files, err := fs.LsF(d)
				if err != nil {
					http.Error(w, err.Error(), http.StatusInternalServerError)
					return
				}
				for _, f := range files {
					key := strings.Split(path.Base(f), ".")[0]
					v := seriesByKey[key]
					switch path.Ext(f) {
					case ".jpg":
						v.Thumbnail = path.Join(path.Base(d), path.Base(f))
					case ".mp4":
						v.HREF = path.Join(path.Base(d), path.Base(f))
					}
					seriesByKey[key] = v
				}
			}
			series := []Series{}
			for _, v := range seriesByKey {
				series = append(series, v)
			}
			slices.SortFunc(series, func(a, b Series) int {
				return -1 * strings.Compare(path.Base(a.Thumbnail), path.Base(b.Thumbnail))
			})

			if err := tmpl.Execute(w, map[string]any{
				"Series": series,
			}); err != nil {
				log.Println(err)
			}
		}),
		BaseContext: func(net.Listener) context.Context {
			return ctx
		},
	}
	defer s.Shutdown(ctx)

	errs := make(chan error)
	go func() {
		defer close(errs)

		errs <- s.ListenAndServe()
	}()

	select {
	case err := <-errs:
		return err
	case <-ctx.Done():
		s.Shutdown(ctx)
		for range errs {
		}
	}
	return nil
}
