package mappers

import (
	"apskel-pos-be/internal/constants"
	"apskel-pos-be/internal/entities"
	"apskel-pos-be/internal/models"
)

func ProductEntityToModel(entity *entities.Product) *models.Product {
	if entity == nil {
		return nil
	}

	return &models.Product{
		ID:             entity.ID,
		OrganizationID: entity.OrganizationID,
		CategoryID:     entity.CategoryID,
		SKU:            entity.SKU,
		Name:           entity.Name,
		Description:    entity.Description,
		Price:          entity.Price,
		Cost:           entity.Cost,
		BusinessType:   constants.BusinessType(entity.BusinessType),
		ImageURL:       entity.ImageURL,
		PrinterType:    entity.PrinterType,
		Metadata:       map[string]interface{}(entity.Metadata),
		IsActive:       entity.IsActive,
		CreatedAt:      entity.CreatedAt,
		UpdatedAt:      entity.UpdatedAt,
	}
}

func ProductModelToEntity(model *models.Product) *entities.Product {
	if model == nil {
		return nil
	}

	return &entities.Product{
		ID:             model.ID,
		OrganizationID: model.OrganizationID,
		CategoryID:     model.CategoryID,
		SKU:            model.SKU,
		Name:           model.Name,
		Description:    model.Description,
		Price:          model.Price,
		Cost:           model.Cost,
		BusinessType:   string(model.BusinessType),
		ImageURL:       model.ImageURL,
		PrinterType:    model.PrinterType,
		Metadata:       entities.Metadata(model.Metadata),
		IsActive:       model.IsActive,
		CreatedAt:      model.CreatedAt,
		UpdatedAt:      model.UpdatedAt,
	}
}

func CreateProductRequestToEntity(req *models.CreateProductRequest) *entities.Product {
	if req == nil {
		return nil
	}

	cost := float64(0)
	if req.Cost > 0 {
		cost = req.Cost
	}

	businessType := "restaurant"
	if req.BusinessType != "" {
		businessType = string(req.BusinessType)
	}

	printerType := "kitchen"
	if req.PrinterType != nil && *req.PrinterType != "" {
		printerType = *req.PrinterType
	}

	metadata := entities.Metadata{}
	if req.Metadata != nil {
		metadata = entities.Metadata(req.Metadata)
	}

	return &entities.Product{
		OrganizationID: req.OrganizationID,
		CategoryID:     req.CategoryID,
		SKU:            req.SKU,
		Name:           req.Name,
		Description:    req.Description,
		Price:          req.Price,
		Cost:           cost,
		BusinessType:   businessType,
		ImageURL:       req.ImageURL,
		PrinterType:    printerType,
		Metadata:       metadata,
		IsActive:       true, // Default to active
	}
}

func ProductEntityToResponse(entity *entities.Product) *models.ProductResponse {
	if entity == nil {
		return nil
	}

	// Convert variants to response models
	var variantResponses []models.ProductVariantResponse
	if entity.ProductVariants != nil {
		variantResponses = make([]models.ProductVariantResponse, len(entity.ProductVariants))
		for i, variant := range entity.ProductVariants {
			variantResponses[i] = models.ProductVariantResponse{
				ID:            variant.ID,
				ProductID:     variant.ProductID,
				Name:          variant.Name,
				PriceModifier: variant.PriceModifier,
				Cost:          variant.Cost,
				Metadata:      map[string]interface{}(variant.Metadata),
				CreatedAt:     variant.CreatedAt,
				UpdatedAt:     variant.UpdatedAt,
			}
		}
	}

	return &models.ProductResponse{
		ID:             entity.ID,
		OrganizationID: entity.OrganizationID,
		CategoryID:     entity.CategoryID,
		SKU:            entity.SKU,
		Name:           entity.Name,
		Description:    entity.Description,
		Price:          entity.Price,
		Cost:           entity.Cost,
		BusinessType:   constants.BusinessType(entity.BusinessType),
		ImageURL:       entity.ImageURL,
		PrinterType:    entity.PrinterType,
		Metadata:       map[string]interface{}(entity.Metadata),
		IsActive:       entity.IsActive,
		CreatedAt:      entity.CreatedAt,
		UpdatedAt:      entity.UpdatedAt,
		Variants:       variantResponses,
	}
}

func UpdateProductEntityFromRequest(entity *entities.Product, req *models.UpdateProductRequest) {
	if entity == nil || req == nil {
		return
	}

	if req.CategoryID != nil {
		entity.CategoryID = *req.CategoryID
	}

	if req.SKU != nil {
		entity.SKU = req.SKU
	}

	if req.Name != nil {
		entity.Name = *req.Name
	}

	if req.Description != nil {
		entity.Description = req.Description
	}

	if req.Price != nil {
		entity.Price = *req.Price
	}

	if req.Cost != nil {
		entity.Cost = *req.Cost
	}

	if req.ImageURL != nil {
		entity.ImageURL = req.ImageURL
	}

	if req.PrinterType != nil {
		entity.PrinterType = *req.PrinterType
	}

	if req.Metadata != nil {
		if entity.Metadata == nil {
			entity.Metadata = make(entities.Metadata)
		}
		for k, v := range req.Metadata {
			entity.Metadata[k] = v
		}
	}

	if req.IsActive != nil {
		entity.IsActive = *req.IsActive
	}
}

func ProductEntitiesToModels(entities []*entities.Product) []*models.Product {
	if entities == nil {
		return nil
	}

	models := make([]*models.Product, len(entities))
	for i, entity := range entities {
		models[i] = ProductEntityToModel(entity)
	}
	return models
}

func ProductEntitiesToResponses(entities []*entities.Product) []*models.ProductResponse {
	if entities == nil {
		return nil
	}

	responses := make([]*models.ProductResponse, len(entities))
	for i, entity := range entities {
		responses[i] = ProductEntityToResponse(entity)
	}
	return responses
}

// Product Variant Mappers
func ProductVariantEntityToModel(entity *entities.ProductVariant) *models.ProductVariant {
	if entity == nil {
		return nil
	}

	return &models.ProductVariant{
		ID:            entity.ID,
		ProductID:     entity.ProductID,
		Name:          entity.Name,
		PriceModifier: entity.PriceModifier,
		Cost:          entity.Cost,
		Metadata:      map[string]interface{}(entity.Metadata),
		CreatedAt:     entity.CreatedAt,
		UpdatedAt:     entity.UpdatedAt,
	}
}

func ProductVariantModelToEntity(model *models.ProductVariant) *entities.ProductVariant {
	if model == nil {
		return nil
	}

	return &entities.ProductVariant{
		ID:            model.ID,
		ProductID:     model.ProductID,
		Name:          model.Name,
		PriceModifier: model.PriceModifier,
		Cost:          model.Cost,
		Metadata:      entities.Metadata(model.Metadata),
		CreatedAt:     model.CreatedAt,
		UpdatedAt:     model.UpdatedAt,
	}
}

func CreateProductVariantRequestToEntity(req *models.CreateProductVariantRequest) *entities.ProductVariant {
	if req == nil {
		return nil
	}

	metadata := entities.Metadata{}
	if req.Metadata != nil {
		metadata = entities.Metadata(req.Metadata)
	}

	return &entities.ProductVariant{
		ProductID:     req.ProductID,
		Name:          req.Name,
		PriceModifier: req.PriceModifier,
		Cost:          req.Cost,
		Metadata:      metadata,
	}
}

func ProductVariantEntityToResponse(entity *entities.ProductVariant) *models.ProductVariantResponse {
	if entity == nil {
		return nil
	}

	return &models.ProductVariantResponse{
		ID:            entity.ID,
		ProductID:     entity.ProductID,
		Name:          entity.Name,
		PriceModifier: entity.PriceModifier,
		Cost:          entity.Cost,
		Metadata:      map[string]interface{}(entity.Metadata),
		CreatedAt:     entity.CreatedAt,
		UpdatedAt:     entity.UpdatedAt,
	}
}

func UpdateProductVariantEntityFromRequest(entity *entities.ProductVariant, req *models.UpdateProductVariantRequest) {
	if entity == nil || req == nil {
		return
	}

	if req.Name != nil {
		entity.Name = *req.Name
	}

	if req.PriceModifier != nil {
		entity.PriceModifier = *req.PriceModifier
	}

	if req.Cost != nil {
		entity.Cost = *req.Cost
	}

	if req.Metadata != nil {
		if entity.Metadata == nil {
			entity.Metadata = make(entities.Metadata)
		}
		for k, v := range req.Metadata {
			entity.Metadata[k] = v
		}
	}
}

func ProductVariantEntitiesToModels(entities []*entities.ProductVariant) []*models.ProductVariant {
	if entities == nil {
		return nil
	}

	models := make([]*models.ProductVariant, len(entities))
	for i, entity := range entities {
		models[i] = ProductVariantEntityToModel(entity)
	}
	return models
}

func ProductVariantEntitiesToResponses(entities []*entities.ProductVariant) []*models.ProductVariantResponse {
	if entities == nil {
		return nil
	}

	responses := make([]*models.ProductVariantResponse, len(entities))
	for i, entity := range entities {
		responses[i] = ProductVariantEntityToResponse(entity)
	}
	return responses
}
