package httpserver

import (
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/go-chi/chi/v5"

	authservice "update_server/internal/auth"
	"update_server/internal/db"
	"update_server/internal/slug"
)

func (h *handler) basePageData(r *http.Request, title, eyebrow, heading, description string) PageData {
	return PageData{
		Title:       title,
		Eyebrow:     eyebrow,
		Heading:     heading,
		Description: description,
		BaseURL:     strings.TrimRight(h.config.BaseURL, "/"),
		CSRFToken:   h.csrfToken(r),
		CurrentUser: h.currentUser(r),
	}
}

func (h *handler) currentUser(r *http.Request) *db.User {
	sessionState, ok := authservice.FromContext(r.Context())
	if !ok {
		return nil
	}

	user := sessionState.User
	return &user
}

func (h *handler) currentUserID(r *http.Request) *int64 {
	user := h.currentUser(r)
	if user == nil {
		return nil
	}

	return &user.ID
}

func routeID(r *http.Request, key string) (int64, error) {
	raw := strings.TrimSpace(chi.URLParam(r, key))
	if raw == "" {
		return 0, fmt.Errorf("%s is required", key)
	}

	value, err := strconv.ParseInt(raw, 10, 64)
	if err != nil || value <= 0 {
		return 0, fmt.Errorf("invalid %s", key)
	}

	return value, nil
}

func projectFormInput(name, slugValue, description string) (db.CreateProjectParams, string) {
	name = strings.TrimSpace(name)
	slugValue = slug.Make(firstNonEmpty(slugValue, name))
	description = strings.TrimSpace(description)

	switch {
	case name == "":
		return db.CreateProjectParams{}, "Project name is required."
	case slugValue == "":
		return db.CreateProjectParams{}, "Project slug is required."
	default:
		return db.CreateProjectParams{
			Name:        name,
			Slug:        slugValue,
			Description: description,
		}, ""
	}
}

func tagFormInput(name, slugValue, description string) (db.CreateTagParams, string) {
	name = strings.TrimSpace(name)
	slugValue = slug.Make(firstNonEmpty(slugValue, name))
	description = strings.TrimSpace(description)

	switch {
	case name == "":
		return db.CreateTagParams{}, "Tag name is required."
	case slugValue == "":
		return db.CreateTagParams{}, "Tag slug is required."
	default:
		return db.CreateTagParams{
			Name:        name,
			Slug:        slugValue,
			Description: description,
		}, ""
	}
}

func firstNonEmpty(values ...string) string {
	for _, value := range values {
		if trimmed := strings.TrimSpace(value); trimmed != "" {
			return trimmed
		}
	}

	return ""
}

func maxUploadMegabytes(bytes int64) int64 {
	if bytes <= 0 {
		return 0
	}

	const mebibyte = 1024 * 1024
	value := bytes / mebibyte
	if bytes%mebibyte != 0 {
		value++
	}
	if value == 0 {
		value = 1
	}

	return value
}

func maxUploadRequestLimit(fileLimit int64) int64 {
	const multipartOverhead = 1 << 20
	return fileLimit + multipartOverhead
}

func isMaxBytesError(err error) bool {
	var maxErr *http.MaxBytesError
	return errors.As(err, &maxErr)
}
