package handlers

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

	"github.com/a-h/templ"
	"github.com/gin-gonic/gin"
	domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
	domain "github.com/haydenhargreaves/Potion/internal/domain/server"
	domainServer "github.com/haydenhargreaves/Potion/internal/domain/server"
	layouts "github.com/haydenhargreaves/Potion/internal/templates/layouts"
	pages "github.com/haydenhargreaves/Potion/internal/templates/pages"
	templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
)

func LoginPage(ctx *gin.Context) {
	title := "Potion - Login"
	page := pages.LoginPage()

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

func HomePage(ctx *gin.Context) {
	deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)

	loggedIn := domain.IsLoggedIn(ctx)

	var page templ.Component
	if loggedIn {
		userId := ctx.MustGet("userId").(int)
		madeRecipes, err := deps.RecipeService.GetUserMadeRecipes(userId, 6)
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"status":  http.StatusInternalServerError,
				"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
			})
			return
		}
		viewedRecipes, err := deps.RecipeService.GetUserViewedRecipes(userId, 6)
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"status":  http.StatusInternalServerError,
				"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
			})
			return
		}

		page = templates.HomePage(true, viewedRecipes, madeRecipes)
	} else {
		page = templates.HomePage(false, nil, nil)
	}

	title := "Potion - Home"

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

func FavoritesPage(ctx *gin.Context) {
	// If not logged in, direct to the login page
	if !domainServer.IsLoggedIn(ctx) {
		ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
		return
	}

	title := "Potion - Favorites"
	var page templ.Component

	// Get filters from cookies
	if bytes, err := ctx.Cookie("search-filters"); err != nil {
		fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
		page = pages.FavoritesPage(domainRecipe.SearchFilters{})
	} else {
		var filters domainRecipe.SearchFilters
		if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
			fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
			page = pages.FavoritesPage(domainRecipe.SearchFilters{})
		} else {
			page = pages.FavoritesPage(filters)
		}
	}

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

func CreatePage(ctx *gin.Context) {
	// If not logged in, direct to the login page
	if !domainServer.IsLoggedIn(ctx) {
		ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
		return
	}

	title := "Potion - Create"
	page := pages.CreatePage()

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

func ProfilePage(ctx *gin.Context) {
	// If not logged in, direct to the login page
	if !domainServer.IsLoggedIn(ctx) {
		ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN)
		return
	}

	// Else, get the user data
	deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
	user := deps.UserService.GetAuthenicatedUser(ctx)
	recipes, err := deps.RecipeService.GetUserRecipes(user.Id)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"status":  http.StatusInternalServerError,
			"message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()),
		})
		return
	}

	favorites, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"status":  http.StatusInternalServerError,
			"message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()),
		})
		return
	}

	// Get the engagement data, not sure what will happen when errors occur
	engagements, err := deps.EngagementService.GetUserEngagement(user.Id, 6)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"status":  http.StatusInternalServerError,
			"message": fmt.Sprintf("Error getting user engagements. %s\n", err.Error()),
		})
		return
	}

	title := "Potion - Profile"
	page := pages.ProfilePage(user, recipes, favorites, engagements)

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

func ListPage(ctx *gin.Context) {
	title := "Potion - Shopping List"
	page := pages.ListPage()

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

// TODO: Figure out how to handle errors, think we just need a simple display.
func RecipePage(ctx *gin.Context) {
	// Call recipe service to get via ID
	deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies)
	id := ctx.Param("id")

	// Parse ID
	parsed, err := strconv.Atoi(id)
	if err != nil {
		fmt.Printf("ERROR: %s\n", err.Error())
		ctx.JSON(400, err.Error())
		return
	}

	// Get signed in user, if they exist
	var userId *int = nil
	var loggedIn = domainServer.IsLoggedIn(ctx)
	if loggedIn {
		storeId := ctx.MustGet("userId").(int)
		userId = &storeId
	}

	// Get recipe
	recipe, err := deps.RecipeService.GetRecipe(parsed, userId)
	if err != nil {
		fmt.Printf("ERROR: %s\n", err.Error())
		ctx.JSON(400, err.Error())
		return
	}

	// Get user (owner)
	user, err := deps.UserService.GetUser(recipe.UserId)
	if err != nil {
		fmt.Printf("ERROR: %s\n", err.Error())
		ctx.JSON(400, err.Error())
		return
	}

	title := "Potion - View Recipe"
	page := pages.RecipePage(*recipe, *user, loggedIn, deps.EnvironmentConfig.Domain)

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

func SearchPage(ctx *gin.Context) {
	var page templ.Component
	// Get filters from cookies
	if bytes, err := ctx.Cookie("search-filters"); err != nil {
		fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
		page = pages.SearchPage(domainRecipe.SearchFilters{}, false)
	} else {
		var filters domainRecipe.SearchFilters
		if err := json.Unmarshal([]byte(bytes), &filters); err != nil {
			fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error())
			page = pages.SearchPage(domainRecipe.SearchFilters{}, false)
		} else {
			page = pages.SearchPage(filters, true)
		}
	}

	title := "Potion - Recipe Search"

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

func NotFoundPage(ctx *gin.Context) {
	title := "Potion - Not Found"
	page := pages.NotFoundPage()

	ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
