package handlers

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

	"github.com/labstack/echo/v4"
	"gorm.io/gorm"

	appmiddleware "git.ma-al.com/goc_marek/ps_shop/internal/http/middleware"
	pscart "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cart"
	pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
	psconfig "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/config"
	pscustomer "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/customer"
	psroutes "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/routes"
	"git.ma-al.com/goc_marek/ps_shop/internal/render"
	"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
)

const productSlugContextKey = "product_slug"
const productIDContextKey = "product_id"

type ProductHandler struct {
	products   *pscatalog.Service
	customers  *pscustomer.Service
	carts      *pscart.Service
	renderer   *render.Engine
	config     psconfig.Config
	categories *psroutes.CategoryRoute
}

func NewProductHandler(products *pscatalog.Service, customers *pscustomer.Service, carts *pscart.Service, renderer *render.Engine, cfg psconfig.Config, categories *psroutes.CategoryRoute) *ProductHandler {
	return &ProductHandler{
		products:   products,
		customers:  customers,
		carts:      carts,
		renderer:   renderer,
		config:     cfg,
		categories: categories,
	}
}

func (h *ProductHandler) Show(c echo.Context) error {
	session := appmiddleware.GetSession(c)
	if h == nil || h.products == nil || h.renderer == nil {
		return echo.NewHTTPError(http.StatusInternalServerError, "product handler is not initialized")
	}

	languageID := int64Default(session.LanguageID, 1)
	languageID = h.products.ResolveLanguageID(c.Request().Context(), c.Request(), languageID)
	shopID := int64Default(session.ShopID, 1)

	product, err := h.products.GetProductPage(c.Request().Context(), pscatalog.ProductPageRequest{
		ID:         productID(c),
		Slug:       productSlug(c),
		LanguageID: languageID,
		ShopID:     shopID,
	})
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return echo.NewHTTPError(http.StatusNotFound, "product not found")
		}
		return err
	}

	var profile *pscustomer.Profile
	if session.CustomerID != nil && h.customers != nil {
		profile, err = h.customers.GetByID(c.Request().Context(), *session.CustomerID)
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			return err
		}
	}

	var cartSummary *pscart.Summary
	if session.CartID != nil && h.carts != nil {
		cartSummary, err = h.carts.SummaryByID(c.Request().Context(), *session.CartID)
		if err != nil {
			return err
		}
	}

	page := viewmodel.ProductPageData{
		Product:     *product,
		CategoryURL: productCategoryURL(c.Request(), h.categories, product),
		Session:     session,
		Customer:    profile,
		CartSummary: cartSummary,
		ShopBaseURL: h.config.PrestaShopBaseURL,
	}
	menu, err := loadMenu(c.Request(), h.products, h.categories, languageID, shopID)
	if err != nil {
		return echo.NewHTTPError(http.StatusInternalServerError, "menu query failed: "+err.Error())
	}
	page.Menu = menu
	locale, err := loadHeaderLocale(c.Request(), h.products, session, languageID)
	if err != nil {
		return echo.NewHTTPError(http.StatusInternalServerError, "locale query failed: "+err.Error())
	}
	page.Locale = locale

	return h.renderer.Product(c.Response(), c.Request(), page)
}

func int64Default(value *int64, fallback int64) int64 {
	if value == nil || *value == 0 {
		return fallback
	}
	return *value
}

func SetProductSlug(c echo.Context, slug string) {
	c.Set(productSlugContextKey, slug)
}

func SetProductID(c echo.Context, id int64) {
	c.Set(productIDContextKey, id)
}

func productSlug(c echo.Context) string {
	if value := c.Get(productSlugContextKey); value != nil {
		if slug, ok := value.(string); ok && slug != "" {
			return slug
		}
	}
	return strings.TrimSpace(c.Param("slug"))
}

func productID(c echo.Context) int64 {
	if value := c.Get(productIDContextKey); value != nil {
		if id, ok := value.(int64); ok {
			return id
		}
	}
	return 0
}

func productCategoryURL(req *http.Request, route *psroutes.CategoryRoute, product *pscatalog.ProductPageData) string {
	if route == nil || product == nil || product.CategoryID == 0 {
		return ""
	}
	return route.BuildPath(psroutes.CategoryURLData{
		ID:             product.CategoryID,
		Slug:           product.CategorySlug,
		LanguagePrefix: requestLanguagePrefix(req),
	})
}
