package main

import (
	"database/sql"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

func getSessionUser(c *gin.Context) *User {
	cookie, err := c.Cookie("session")
	if err != nil || cookie == "" {
		return nil
	}
	var s Session
	if err := db.Preload("User").Where("token = ?", cookie).First(&s).Error; err != nil {
		return nil
	}
	return &s.User
}

func requireAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		if u := getSessionUser(c); u != nil {
			c.Set("user", u)
			c.Next()
			return
		}
		c.Redirect(http.StatusFound, "/login")
		c.Abort()
	}
}

func setSessionCookie(c *gin.Context, token string) {
	// Very long-lived cookie (~10 years)
	maxAge := 10 * 365 * 24 * 60 * 60
	httpOnly := true
	secure := strings.HasPrefix(baseURL, "https://")
	sameSite := http.SameSiteLaxMode
	c.SetCookie("session", token, maxAge, "/", cookieDomain, secure, httpOnly)
	// Workaround to set SameSite explicitly via header
	c.Header("Set-Cookie", (&http.Cookie{Name: "session", Value: token, Path: "/", Domain: cookieDomain, MaxAge: maxAge, Secure: secure, HttpOnly: httpOnly, SameSite: sameSite}).String())
}

func findOrCreateUserByHandle(handle string) (*User, error) {
	h := strings.TrimSpace(handle)
	if h == "" {
		return nil, sql.ErrNoRows
	}
	if strings.Contains(h, "@") { // email
		if u, err := userByEmail(strings.ToLower(h)); err == nil {
			return u, nil
		}
		// create
		u := &User{Email: strings.ToLower(h), Username: defaultUsername()}
		if err := ensureUniqueUsernameAndSlug(u); err != nil {
			return nil, err
		}
		if err := db.Create(u).Error; err != nil {
			return nil, err
		}
		return u, nil
	}
	// username
	var u User
	if err := db.Where("username = ?", h).First(&u).Error; err == nil {
		return &u, nil
	}
	// If not found, create placeholder user with random email-like token
	u = User{Email: mustRandToken(3) + "+placeholder@local", Username: h, Slug: slugify(h)}
	if err := ensureUniqueUsernameAndSlug(&u); err != nil { /* best-effort */
	}
	if err := db.Create(&u).Error; err != nil {
		return nil, err
	}
	return &u, nil
}
