package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"testing"

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

func TestMainDelegatesToRunApp(t *testing.T) {
	origRun := run
	origFatal := fatal
	defer func() {
		run = origRun
		fatal = origFatal
	}()

	called := false
	run = func() error {
		called = true
		return http.ErrNoCookie
	}
	fatal = func(args ...any) {
		called = true
	}

	main()

	if !called {
		t.Fatalf("expected main to delegate to runApp")
	}
}

func TestRunInitializesServer(t *testing.T) {
	t.Setenv("PEGASUS_SESSION_KEY", "test-session-key")
	origServeHTTP := serveHTTP
	origMediaRoot := mediaRoot
	origUserMapFile := userMapFile
	origTusDir := tusDir
	origDebug := internal.Debug
	defer func() {
		serveHTTP = origServeHTTP
		mediaRoot = origMediaRoot
		userMapFile = origUserMapFile
		tusDir = origTusDir
		internal.Debug = origDebug
	}()

	workDir := t.TempDir()
	mediaRoot = filepath.Join(workDir, "media")
	tusDir = filepath.Join(workDir, "tus")
	userMapFile = filepath.Join(workDir, "user-map.yaml")
	internal.Debug = false

	if err := os.MkdirAll(filepath.Join(mediaRoot, "library"), 0o2775); err != nil {
		t.Fatalf("mkdir media root: %v", err)
	}
	mapBody := "map:\n  brad: library\n"
	for i := 0; i < 11; i++ {
		mapBody += fmt.Sprintf("  user%02d: library\n", i)
	}
	if err := os.WriteFile(userMapFile, []byte(mapBody), 0o644); err != nil {
		t.Fatalf("write user map: %v", err)
	}

	var gotServer *http.Server
	serveHTTP = func(srv *http.Server) error {
		gotServer = srv
		return nil
	}

	if err := run(); err != nil {
		t.Fatalf("run returned error: %v", err)
	}
	if gotServer == nil {
		t.Fatalf("expected server to be created")
	}
	if gotServer.Addr != ":8080" {
		t.Fatalf("unexpected default address %q", gotServer.Addr)
	}
	if gotServer.Handler == nil {
		t.Fatalf("expected handler to be configured")
	}
	if _, err := os.Stat(tusDir); err != nil {
		t.Fatalf("expected tus dir to be created: %v", err)
	}
}

func TestRunDebugLogging(t *testing.T) {
	t.Setenv("PEGASUS_SESSION_KEY", "test-session-key")
	origServeHTTP := serveHTTP
	origMediaRoot := mediaRoot
	origUserMapFile := userMapFile
	origTusDir := tusDir
	origDebug := internal.Debug
	defer func() {
		serveHTTP = origServeHTTP
		mediaRoot = origMediaRoot
		userMapFile = origUserMapFile
		tusDir = origTusDir
		internal.Debug = origDebug
	}()

	workDir := t.TempDir()
	mediaRoot = filepath.Join(workDir, "media")
	tusDir = filepath.Join(workDir, "tus")
	userMapFile = filepath.Join(workDir, "user-map.yaml")
	internal.Debug = true

	if err := os.MkdirAll(filepath.Join(mediaRoot, "library"), 0o2775); err != nil {
		t.Fatalf("mkdir media root: %v", err)
	}
	mapBody := "map:\n  brad: library\n"
	for i := 0; i < 11; i++ {
		mapBody += fmt.Sprintf("  user%02d: library\n", i)
	}
	if err := os.WriteFile(userMapFile, []byte(mapBody), 0o644); err != nil {
		t.Fatalf("write user map: %v", err)
	}

	serveHTTP = func(srv *http.Server) error { return nil }
	if err := run(); err != nil {
		t.Fatalf("run returned error: %v", err)
	}
}

func TestRunRejectsMissingSessionKey(t *testing.T) {
	t.Setenv("PEGASUS_SESSION_KEY", "")
	origServeHTTP := serveHTTP
	origMediaRoot := mediaRoot
	origUserMapFile := userMapFile
	origTusDir := tusDir
	defer func() {
		serveHTTP = origServeHTTP
		mediaRoot = origMediaRoot
		userMapFile = origUserMapFile
		tusDir = origTusDir
	}()

	serveHTTP = func(srv *http.Server) error {
		t.Fatalf("serveHTTP should not be called")
		return nil
	}
	if err := run(); err == nil {
		t.Fatalf("expected missing session key error")
	}
}

func TestRunRejectsMissingUserMap(t *testing.T) {
	t.Setenv("PEGASUS_SESSION_KEY", "test-session-key")
	origServeHTTP := serveHTTP
	origMediaRoot := mediaRoot
	origUserMapFile := userMapFile
	origTusDir := tusDir
	defer func() {
		serveHTTP = origServeHTTP
		mediaRoot = origMediaRoot
		userMapFile = origUserMapFile
		tusDir = origTusDir
	}()

	workDir := t.TempDir()
	mediaRoot = filepath.Join(workDir, "media")
	tusDir = filepath.Join(workDir, "tus")
	userMapFile = filepath.Join(workDir, "missing.yaml")
	serveHTTP = func(srv *http.Server) error {
		t.Fatalf("serveHTTP should not be called")
		return nil
	}

	if err := run(); err == nil {
		t.Fatalf("expected load user map error")
	}
}

func TestRunRejectsTusDirCreationFailure(t *testing.T) {
	t.Setenv("PEGASUS_SESSION_KEY", "test-session-key")
	origServeHTTP := serveHTTP
	origMediaRoot := mediaRoot
	origUserMapFile := userMapFile
	origTusDir := tusDir
	origDebug := internal.Debug
	defer func() {
		serveHTTP = origServeHTTP
		mediaRoot = origMediaRoot
		userMapFile = origUserMapFile
		tusDir = origTusDir
		internal.Debug = origDebug
	}()

	workDir := t.TempDir()
	mediaRoot = filepath.Join(workDir, "media")
	userMapFile = filepath.Join(workDir, "user-map.yaml")
	_ = os.WriteFile(userMapFile, []byte("map:\n  brad: library\n"), 0o644)
	filePath := filepath.Join(workDir, "not-a-dir")
	_ = os.WriteFile(filePath, []byte("file"), 0o644)
	tusDir = filepath.Join(filePath, "sub")
	internal.Debug = false
	serveHTTP = func(srv *http.Server) error {
		t.Fatalf("serveHTTP should not be called")
		return nil
	}

	if err := run(); err == nil {
		t.Fatalf("expected tus dir creation error")
	}
}

func TestMustDoesNotExitOnNil(t *testing.T) {
	must(nil, "noop")
}
