package server

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
	domain "github.com/haydenhargreaves/Potion/internal/domain/server"
	"github.com/haydenhargreaves/Potion/internal/templates/components"
	templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
)

const CREATE_ERROR_HTML = `
	<p id="response" class="text-sm text-red-500 px-4 py-1 bg-red-100 rounded-full w-fit">
		Uh oh! Something went wrong when creating your recipe. Please try again. %s
	</p>
`

func (s *Server) CreateRecipeHandler(ctx *gin.Context) {
	recipe, err := s.deps.RecipeService.CreateRecipe(ctx)
	if err != nil {
		components.RenderErrorBanner(ctx, err.Error())
		ctx.String(http.StatusOK, CREATE_ERROR_HTML, err.Error())
		return
	}

	// Send HTMX redirection
	url := fmt.Sprintf(domain.WEB_RECIPE, recipe.Id)
	ctx.Header("HX-Redirect", url)
	ctx.Status(http.StatusCreated)
}

// toBits converts an array of stringified numbers into a single summed value
func toBits(arr []string) (bits int) {
	for _, x := range arr {
		num, _ := strconv.Atoi(x)
		bits += num
	}
	return
}

// TODO: (7/06/2025) I don't love doing all of this here, but it seems to be the only way to get it to work...
func (s *Server) SearchRecipesHandler(ctx *gin.Context) {
	// create filters
	filters := domainRecipe.SearchFilters{
		Search:      ctx.PostForm("search"), // string, search query for titles
		MealType:    toBits(ctx.PostFormArray("meal")),
		Time:        toBits(ctx.PostFormArray("time")),
		Difficulty:  toBits(ctx.PostFormArray("difficulty")),
		ServingSize: toBits(ctx.PostFormArray("serving")),
	}

	// Set the filters into the cookies, so they can be reloaded
	if bytes, err := json.Marshal(filters); err == nil {
		s.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24)
	}

	redirect := ctx.PostForm("redirect")
	if redirect == "true" {
		ctx.Header("HX-Redirect", domain.WEB_SEARCH)
		ctx.Status(http.StatusOK)
		return
	}

	// Get user if logged in, so we can get favorite status
	var userId *int = nil
	if domain.IsLoggedIn(ctx) {
		id := ctx.MustGet("userId").(int)
		userId = &id
	}

	// TODO: Not sure if we need to ensure the user is valid here

	// We don't care about favorite status, so use false
	recipes, err := s.deps.RecipeService.SearchRecipes(filters, userId, false)
	if err != nil {
		components.RenderErrorBanner(ctx, err.Error())
		ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
	}

	// Render content as the response
	ctx.Status(200)
	templates.ResultList(recipes).Render(ctx.Request.Context(), ctx.Writer)
}

func (s *Server) SearchRecipesFavoritesHandler(ctx *gin.Context) {
	// create filters
	filters := domainRecipe.SearchFilters{
		Search:      ctx.PostForm("search"), // string, search query for titles
		MealType:    toBits(ctx.PostFormArray("meal")),
		Time:        toBits(ctx.PostFormArray("time")),
		Difficulty:  toBits(ctx.PostFormArray("difficulty")),
		ServingSize: toBits(ctx.PostFormArray("serving")),
	}

	// Set the filters into the cookies, so they can be reloaded
	if bytes, err := json.Marshal(filters); err == nil {
		s.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24)
	}

	if !domain.IsLoggedIn(ctx) {
		components.RenderErrorBanner(ctx, "User is not logged in. User will be nil.")
		ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."})
	}

	userId := ctx.MustGet("userId").(int)

	recipes, err := s.deps.RecipeService.SearchRecipes(filters, &userId, true)
	if err != nil {
		components.RenderErrorBanner(ctx, err.Error())
		ctx.JSON(http.StatusOK, gin.H{"error": err.Error()})
	}

	// Render content as the response
	ctx.Status(200)
	templates.FavoriteList(recipes).Render(ctx.Request.Context(), ctx.Writer)
}
