package handlers

import (
	"errors"
	"net/http"
	"sort"
	"strings"

	"github.com/gin-gonic/gin"

	"sproutgate-backend/internal/auth"
	"sproutgate-backend/internal/models"
	"sproutgate-backend/internal/storage"
)

// ListPublicUsers 公开用户目录（未封禁用户，默认按注册时间从早到晚）。
func (h *Handler) ListPublicUsers(c *gin.Context) {
	users, err := h.store.ListUsers()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load users"})
		return
	}
	out := make([]models.PublicUserListEntry, 0, len(users))
	for _, u := range users {
		if u.Banned {
			continue
		}
		out = append(out, u.PublicListEntry())
	}
	sort.Slice(out, func(i, j int) bool {
		return strings.TrimSpace(out[i].CreatedAt) < strings.TrimSpace(out[j].CreatedAt)
	})
	c.JSON(http.StatusOK, gin.H{"total": len(out), "users": out})
}

func (h *Handler) GetPublicUser(c *gin.Context) {
	account := strings.TrimSpace(c.Param("account"))
	if account == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "account is required"})
		return
	}
	users, err := h.store.ListUsers()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load users"})
		return
	}
	for _, user := range users {
		if strings.EqualFold(strings.TrimSpace(user.Account), account) {
			if user.Banned {
				c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
				return
			}
			likeCount, err := h.store.CountProfileLikes(user.Account)
			if err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load likes"})
				return
			}
			payload := gin.H{
				"user":             user.PublicProfile(),
				"profileLikeCount": likeCount,
			}
			if token := bearerToken(c.GetHeader("Authorization")); token != "" {
				claims, err := auth.ParseToken(h.store.JWTSecret(), h.store.JWTIssuer(), token)
				if err == nil {
					viewer, vFound, vErr := h.store.GetUser(claims.Account)
					if vErr == nil && vFound && !viewer.Banned && claims.TokenEpoch == viewer.TokenEpoch {
						if strings.EqualFold(viewer.Account, user.Account) {
							payload["viewerIsOwner"] = true
						} else {
							has, _ := h.store.ViewerHasLikedProfileToday(viewer.Account, user.Account)
							payload["viewerHasLikedToday"] = has
							rem, _ := h.store.ProfileLikeRemainingToday(viewer.Account)
							payload["viewerLikesRemainingToday"] = rem
							payload["profileLikeDailyMax"] = storage.MaxProfileLikesPerDay
						}
					}
				}
			}
			c.JSON(http.StatusOK, payload)
			return
		}
	}
	c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
}

func (h *Handler) PostPublicProfileLike(c *gin.Context) {
	likedParam := strings.TrimSpace(c.Param("account"))
	if likedParam == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "account is required"})
		return
	}
	token := bearerToken(c.GetHeader("Authorization"))
	if token == "" {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "missing token"})
		return
	}
	claims, err := auth.ParseToken(h.store.JWTSecret(), h.store.JWTIssuer(), token)
	if err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
		return
	}
	likerUser, found, err := h.store.GetUser(claims.Account)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load user"})
		return
	}
	if !found {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not found"})
		return
	}
	if abortIfUserBanned(c, likerUser) {
		return
	}
	if abortIfTokenEpochStale(c, claims, likerUser) {
		return
	}

	newCount, err := h.store.AddProfileLike(likerUser.Account, likedParam)
	if err != nil {
		switch {
		case errors.Is(err, storage.ErrCannotLikeOwnProfile):
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		case errors.Is(err, storage.ErrProfileLikeTarget):
			c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
			return
		case errors.Is(err, storage.ErrAlreadyLikedToday):
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		case errors.Is(err, storage.ErrDailyLikeLimitReached):
			rem, _ := h.store.ProfileLikeRemainingToday(likerUser.Account)
			c.JSON(http.StatusBadRequest, gin.H{
				"error":                      err.Error(),
				"viewerLikesRemainingToday": rem,
				"profileLikeDailyMax":        storage.MaxProfileLikesPerDay,
			})
			return
		case errors.Is(err, storage.ErrProfileLikeLiker):
			c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
			return
		default:
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
			return
		}
	}

	rem, _ := h.store.ProfileLikeRemainingToday(likerUser.Account)
	c.JSON(http.StatusOK, gin.H{
		"profileLikeCount":           newCount,
		"viewerHasLikedToday":        true,
		"viewerLikesRemainingToday": rem,
		"profileLikeDailyMax":        storage.MaxProfileLikesPerDay,
	})
}
