package server

import (
	"html/template"
	"time"

	"github.com/gin-contrib/gzip"
	"github.com/gin-gonic/gin"

	"warpbox/lib/boxstore"
	"warpbox/lib/config"
	"warpbox/lib/routing"
)

type App struct {
	config *config.Config
}

func Run(addr string) error {
	cfg, err := config.Load()
	if err != nil {
		return err
	}
	if err := cfg.EnsureDirectories(); err != nil {
		return err
	}

	applyBoxstoreRuntimeConfig(cfg)

	app := &App{config: cfg}

	router := gin.Default()
	htmlTemplates, err := loadHTMLTemplates()
	if err != nil {
		return err
	}
	router.SetHTMLTemplate(htmlTemplates)

	routing.Register(router, routing.Handlers{
		Index:              app.handleIndex,
		ShowBox:            app.handleShowBox,
		BoxLogin:           handleBoxLogin,
		BoxLoginPost:       handleBoxLoginPost,
		BoxStatus:          app.handleBoxStatus,
		DownloadBox:        app.handleDownloadBox,
		DownloadFile:       app.handleDownloadFile,
		DownloadThumbnail:  app.handleDownloadThumbnail,
		CreateBox:          app.handleCreateBox,
		ManifestFileUpload: app.handleManifestFileUpload,
		FileStatusUpdate:   app.handleFileStatusUpdate,
		DirectBoxUpload:    app.handleDirectBoxUpload,
		LegacyUpload:       app.handleLegacyUpload,

		AdminLogin:     app.handleAdminLogin,
		AdminLoginPost: app.handleAdminLoginPost,
		AdminLogout:    app.handleAdminLogout,
		AdminDashboard: app.handleAdminDashboard,
		AdminAlerts:    app.handleAdminAlerts,
		AdminAuth:      app.adminAuthMiddleware,
	})

	compressed := router.Group("/", gzip.Gzip(gzip.DefaultCompression))
	compressed.Static("/static", "./static")

	boxstore.StartThumbnailWorker(cfg.ThumbnailBatchSize, time.Duration(cfg.ThumbnailIntervalSeconds)*time.Second)

	return router.Run(addr)
}

func loadHTMLTemplates() (*template.Template, error) {
	tmpl := template.New("")
	for _, pattern := range []string{
		"templates/*.html",
		"templates/admin/*.html",
		"templates/admin/partials/*.html",
	} {
		var err error
		tmpl, err = tmpl.ParseGlob(pattern)
		if err != nil {
			return nil, err
		}
	}
	return tmpl, nil
}

func applyBoxstoreRuntimeConfig(cfg *config.Config) {
	boxstore.SetUploadRoot(cfg.UploadsDir)
	boxstore.SetOneTimeDownloadExpiry(cfg.OneTimeDownloadExpirySeconds)
}
