package handlers

import (
	"net/http"
	"strconv"

	"warpbox.dev/backend/libs/services"
	"warpbox.dev/backend/libs/web"
)

type homeData struct {
	MaxUploadSize        string
	MaxUploadBytes       int64
	LimitSummary         string
	Collections          []collectionView
	IsAdmin              bool
	AnonymousOpen        bool
	ExpiryOptions        []expiryOption
	DefaultExpiryMinutes int
}

type expiryOption struct {
	Minutes int
	Label   string
}

func (a *App) Home(w http.ResponseWriter, r *http.Request) {
	currentUser := a.currentPublicUser(r)
	var collections []collectionView
	var isAdmin bool
	var user services.User
	var loggedIn bool
	if current, ok := a.currentUser(r); ok {
		user = current
		loggedIn = true
		isAdmin = user.Role == services.UserRoleAdmin
		userCollections, err := a.authService.ListCollections(user.ID)
		if err == nil {
			collections = make([]collectionView, 0, len(userCollections))
			for _, collection := range userCollections {
				collections = append(collections, collectionView{ID: collection.ID, Name: collection.Name})
			}
		}
	}
	settings, err := a.settingsService.UploadPolicy()
	if err != nil {
		http.Error(w, "unable to load upload policy", http.StatusInternalServerError)
		return
	}
	actor := "anonymous"
	if loggedIn {
		actor = "user"
	}
	a.logger.Info("upload page viewed", withRequestLogAttrs(r,
		"source", "page",
		"severity", "user_activity",
		"code", 2500,
		"actor", actor,
		"user_id", user.ID,
	)...)
	maxUploadSize, maxUploadBytes, limitSummary := a.homeUploadPolicyLabels(settings, user, loggedIn, isAdmin)
	expiryOptions, defaultExpiry := a.homeExpiryOptions(settings, user, loggedIn, isAdmin)
	a.renderPage(w, r, http.StatusOK, "home.html", web.PageData{
		Title:        "Upload your files",
		Description:  "Upload and share files fast. Drop a file, get a link — private, temporary transfers that expire on your terms.",
		CanonicalURL: absoluteURL(r, "/"),
		ImageURL:     absoluteURL(r, "/static/og-default.png"),
		ImageAlt:     "Warp Box — simple file sharing and fast downloads",
		CurrentUser:  currentUser,
		Data: homeData{
			MaxUploadSize:        maxUploadSize,
			MaxUploadBytes:       maxUploadBytes,
			LimitSummary:         limitSummary,
			Collections:          collections,
			IsAdmin:              isAdmin,
			AnonymousOpen:        settings.AnonymousUploadsEnabled,
			ExpiryOptions:        expiryOptions,
			DefaultExpiryMinutes: defaultExpiry,
		},
	})
}

// homeExpiryOptions builds the expiry ladder offered on the upload form, capped to
// the viewer's effective maximum retention. Admins have no cap (the dropdown is
// still capped at 365 days for sanity; the API accepts any value for admins).
func (a *App) homeExpiryOptions(settings services.UploadPolicySettings, user services.User, loggedIn, isAdmin bool) ([]expiryOption, int) {
	maxDays := settings.AnonymousMaxDays
	unlimited := false
	switch {
	case isAdmin:
		unlimited = true
	case loggedIn:
		maxDays = a.settingsService.EffectivePolicyForUser(settings, user).MaxDays
		// A negative per-user MaxDays override means unlimited retention.
		if maxDays < 0 {
			unlimited = true
		}
	}
	return buildExpiryOptions(maxDays, unlimited)
}

func buildExpiryOptions(maxDays int, unlimited bool) ([]expiryOption, int) {
	ladder := []int{60, 360, 720, 1440, 2880, 4320, 7200, 10080, 14400, 20160, 43200, 86400, 129600, 259200, 525600}

	capMinutes := maxDays * 24 * 60
	if unlimited || capMinutes <= 0 {
		capMinutes = 525600
	}

	options := make([]expiryOption, 0, len(ladder)+1)
	seen := make(map[int]bool)
	for _, minutes := range ladder {
		if minutes > capMinutes {
			break
		}
		options = append(options, expiryOption{Minutes: minutes, Label: expiryLabel(minutes)})
		seen[minutes] = true
	}
	// Always offer the exact cap as a final choice (e.g. a 15-day limit).
	if !unlimited && !seen[capMinutes] {
		options = append(options, expiryOption{Minutes: capMinutes, Label: expiryLabel(capMinutes)})
	}
	if len(options) == 0 {
		options = append(options, expiryOption{Minutes: capMinutes, Label: expiryLabel(capMinutes)})
	}
	// Unlimited uploaders can pick "never expires" (sentinel -1) after the ladder.
	if unlimited {
		options = append(options, expiryOption{Minutes: -1, Label: "Unlimited (never expires)"})
	}

	// Default to 24h when available, otherwise the smallest option offered.
	defaultMinutes := options[0].Minutes
	if seen[1440] {
		defaultMinutes = 1440
	}
	return options, defaultMinutes
}

func expiryLabel(minutes int) string {
	switch {
	case minutes < 60:
		return strconv.Itoa(minutes) + " minutes"
	case minutes < 1440:
		hours := minutes / 60
		if hours == 1 {
			return "1 hour"
		}
		return strconv.Itoa(hours) + " hours"
	case minutes == 1440:
		return "24 hours"
	default:
		days := minutes / 1440
		if days == 1 {
			return "1 day"
		}
		return strconv.Itoa(days) + " days"
	}
}

func (a *App) homeUploadPolicyLabels(settings services.UploadPolicySettings, user services.User, loggedIn, isAdmin bool) (string, int64, string) {
	if isAdmin {
		return "No file size limit", -1, "Admin uploads bypass storage and daily caps."
	}
	if !loggedIn {
		if !settings.AnonymousUploadsEnabled {
			return "Anonymous uploads disabled", 0, "Sign in to upload files."
		}
		return services.FormatMegabytesLabel(settings.AnonymousMaxUploadMB), services.MegabytesToBytes(settings.AnonymousMaxUploadMB), "Daily anonymous cap: " + services.FormatMegabytesLabel(settings.AnonymousDailyUploadMB) + " per IP · " + strconv.Itoa(settings.AnonymousMaxDays) + " day max."
	}
	policy := a.settingsService.EffectivePolicyForUser(settings, user)
	maxUpload := a.uploadService.MaxUploadSizeLabel()
	maxUploadBytes := a.uploadService.MaxUploadSize()
	if policy.MaxUploadMB < 0 {
		maxUpload = "unlimited"
		maxUploadBytes = -1
	} else if policy.MaxUploadMB > 0 {
		maxUpload = services.FormatMegabytesLabel(policy.MaxUploadMB)
		maxUploadBytes = services.MegabytesToBytes(policy.MaxUploadMB)
	}
	quota := "unlimited"
	if policy.StorageQuotaSet {
		quota = services.FormatMegabytesLabel(policy.StorageQuotaMB)
	}
	expiryLimit := strconv.Itoa(policy.MaxDays) + " day max."
	if policy.MaxDays < 0 {
		expiryLimit = "no expiry limit."
	}
	return maxUpload, maxUploadBytes, "Daily cap: " + services.FormatMegabytesLabel(policy.DailyUploadMB) + " · Storage quota: " + quota + " · " + expiryLimit
}
