package handlers

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"
	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 CreateRecipe(ctx *gin.Context) {
	deps := ctx.MustGet("deps").(*domain.InjectedDependencies)

	recipe, err := deps.RecipeService.CreateRecipe(ctx)
	if err != nil {
		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: I don't love doing all of this here, but it seems to be the only way to get it to work...
func SearchRecipes(ctx *gin.Context) {
	deps := ctx.MustGet("deps").(*domain.InjectedDependencies)

	// 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 {
		ctx.SetCookie(
			"search-filters",
			string(bytes),
			int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()),
			"/",
			"",    // TODO: Need an actual domain
			false, // TODO: True in prod
			true,
		)
	}

	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
	}

	// We don't care about favorite status, so use false
	recipes, err := deps.RecipeService.SearchRecipes(filters, userId, false)
	if err != nil {
		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 SearchRecipesFavorites(ctx *gin.Context) {
	deps := ctx.MustGet("deps").(*domain.InjectedDependencies)

	// 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 {
		ctx.SetCookie(
			"search-filters",
			string(bytes),
			int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()),
			"/",
			"",    // TODO: Need an actual domain
			false, // TODO: True in prod
			true,
		)
	}

	// TODO: Error here if they're not logged in?
	// Get user data (they should be logged in)
	if !domain.IsLoggedIn(ctx) {
		ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."})
	}

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

	recipes, err := deps.RecipeService.SearchRecipes(filters, &userId, true)
	if err != nil {
		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)
}
