// backend/upload_handler.go
package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/tus/tusd/pkg/filestore"
	handler "github.com/tus/tusd/pkg/handler"
	"github.com/tus/tusd/pkg/memorylocker"

	"scm.bstein.dev/bstein/Pegasus/backend/internal"
)

func newTusHandler(um *internal.UserMap, jf jellyfinClient) *handler.UnroutedHandler {
	store := filestore.FileStore{Path: tusDir}
	locker := memorylocker.New()
	composer := handler.NewStoreComposer()
	store.UseIn(composer)
	locker.UseIn(composer)

	config := handler.Config{
		BasePath:                "/tus/",
		StoreComposer:           composer,
		NotifyCompleteUploads:   true,
		MaxSize:                 8 * 1024 * 1024 * 1024,
		RespectForwardedHeaders: true,
	}
	tusHandler, err := handler.NewUnroutedHandler(config)
	must(err, "init tus handler")

	go watchUploadCompletions(tusHandler.CompleteUploads, um, jf)
	return tusHandler
}

func watchUploadCompletions(completeC <-chan handler.HookEvent, um *internal.UserMap, jf jellyfinClient) {
	for ev := range completeC {
		if err := processCompletedUpload(ev, um, jf); err != nil {
			log.Printf("tus upload processing failed: %v", err)
		}
	}
}

func processCompletedUpload(ev handler.HookEvent, um *internal.UserMap, jf jellyfinClient) error {
	claims, err := claimsFromHook(ev)
	if err != nil {
		internal.Logf("tus: no session: %v", err)
		return err
	}

	meta := ev.Upload.MetaData
	desc := strings.TrimSpace(meta["desc"])
	date := strings.TrimSpace(meta["date"])
	subdir := strings.Trim(strings.TrimSpace(meta["subdir"]), "/")
	lib := strings.Trim(strings.TrimSpace(meta["lib"]), "/")
	orig := meta["filename"]
	if orig == "" {
		orig = "upload.bin"
	}

	ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(orig), "."))
	isVideo := map[string]bool{
		"mp4": true, "mkv": true, "mov": true, "avi": true, "m4v": true,
		"webm": true, "mpg": true, "mpeg": true, "ts": true, "m2ts": true,
	}[ext]
	if isVideo && desc == "" {
		return fmt.Errorf("missing desc for video")
	}
	if desc == "" {
		desc = "upload"
	}

	rootRel, err := resolveLibraryRoot(um, claims.Username, lib)
	if err != nil {
		return err
	}
	libRoot, _ := internal.SafeJoin(mediaRoot, rootRel)
	if fi, err := os.Stat(libRoot); err != nil || !fi.IsDir() {
		return fmt.Errorf("library root missing or not accessible")
	}

	destRoot := libRoot
	if subdir != "" {
		subdir = sanitizeSegment(subdir)
		destRoot = filepath.Join(libRoot, subdir)
		if err := os.MkdirAll(destRoot, 0o2775); err != nil {
			return err
		}
	}

	finalName := composeFinalName(date, desc, orig)
	dst := filepath.Join(destRoot, finalName)
	if err := moveFromTus(ev, dst); err != nil {
		return err
	}

	jf.RefreshLibrary(claims.JFToken)
	return nil
}
