package product_repository

import (
	"chonho/const"
	"chonho/internal/api-v1/entity"
	_error "chonho/pkg/c_error"
	"chonho/pkg/model"
	"database/sql"
	"github.com/reactivex/rxgo/handlers"
	"github.com/reactivex/rxgo/observable"
	"gorm.io/gorm"
)

func (r *repository) FindStoreProduct(filter ProductFilter) ([]entity.FullStoreProduct, error) {
	builder := r.db.Table("store_products sp").
		Joins("LEFT JOIN products p ON sp.product_id = p.id")

	if filter.ProductId != 0 {
		builder = builder.Where("sp.product_id = ?", filter.ProductId)
	}
	if len(filter.ProductIds) > 0 {
		builder = builder.Where("sp.product_id IN (?)", filter.ProductIds)
	}
	if len(filter.Status) > 0 {
		builder = builder.Where("sp.status IN (?)", filter.Status)
	}
	if filter.StoreId != 0 {
		builder = builder.Where("sp.store_id = ?", filter.StoreId)
	}
	if filter.CategoryId != 0 {
		builder = builder.Where("p.category_id = ?", filter.CategoryId)
	}

	var products []entity.FullStoreProduct
	err := builder.Select("sp.*, p.is_quote_after_ordering, p.name, p.thumbnail").Find(&products).Error
	if err != nil {
		return nil, err
	}
	return products, nil
}

func (r *repository) HoldOrderProduct(storeId, orderId int64, productQuantityMap map[int64]int) error {
	tx := r.db.Begin(&sql.TxOptions{
		Isolation: sql.LevelRepeatableRead,
		ReadOnly:  false,
	})

	var obs []observable.Observable
	for id, quan := range productQuantityMap {
		productId := id
		quantity := quan
		obs = append(obs, observable.Start(func() interface{} {
			res := tx.Model(&model.StoreProduct{}).
				Where("store_id = ?", storeId).
				Where("product_id = ?", productId).
				Where("stock - ? >= ?", quantity, 0).
				UpdateColumns(map[string]interface{}{
					"stock": gorm.Expr("stock - ?", quantity),
				})
			if res.Error != nil || res.RowsAffected == 0 {
				return _error.New(_const.ProductOutOfStock, "product out of stock")
			}
			return nil
		}))
	}

	sub := <-observable.ZipAll(obs...).Subscribe(handlers.DoneFunc(func() {

	}))

	if sub.Error != nil {
		tx.Rollback()
		return sub.Error
	}
	var inventoryHis []model.StoreInventoryHistory
	for productId, quantity := range productQuantityMap {
		inventoryHis = append(inventoryHis, model.StoreInventoryHistory{
			StoreProductId: productId,
			Change:         quantity,
			OrderId:        orderId,
		})
	}
	err := r.db.Create(inventoryHis).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit().Error
}
