package product_usecase

import (
	_const "chonho/const"
	"chonho/internal/api-v1/entity"
	"chonho/internal/api-v1/repository/product_repository"
	"chonho/internal/api-v1/repository/store_repository"
	_error "chonho/pkg/c_error"
	"chonho/pkg/model"
	"chonho/util"
	"encoding/json"
	"fmt"
	"sync"
	"time"

	"gorm.io/gorm"
)

func (u *useCase) CreateProductModel(user *model.User, request *entity.AddSellerProductRequest) (*model.Product, error) {
	images, _ := json.Marshal(request.Images)
	product := &model.Product{
		UserId:               user.Id,
		CategoryId:           request.CategoryId,
		Name:                 request.Name,
		Description:          request.Description,
		Unit:                 request.Unit,
		IsQuoteAfterOrdering: request.IsQuoteAfterOrdering,
		Thumbnail:            request.Thumbnail,
		Images:               string(images),
		Status:               _const.ProductStatusAvailable,
	}

	err := u.productRepo.SaveProduct(product)
	if err != nil {
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}
	return product, nil
}

func (u *useCase) CreateStoreProduct(store *model.Store, product *model.Product, request *entity.AddSellerProductRequest) (*model.StoreProduct, error) {
	storeProduct := &model.StoreProduct{
		StoreId:            store.Id,
		ProductId:          product.Id,
		Stock:              request.Stock,
		Price:              request.Price,
		DeliveryType:       request.DeliveryType,
		DeliveryCommitTime: request.DeliveryCommitTime,
		Status:             _const.StoreProductStatusActive,
	}

	err := u.productRepo.SaveStoreProduct(storeProduct)
	if err != nil {
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}
	fmt.Println(storeProduct.Status)
	return storeProduct, nil
}

func (u *useCase) ChangeStock(storeProductId int64, qty int, change int, note string, orderID int64) error {
	return u.productRepo.SaveStockChange(&model.StoreInventoryHistory{
		StoreProductId: storeProductId,
		Change:         change,
		Note:           note,
		Quantity:       qty,
		OrderId:        orderID,
	})
}

func (u *useCase) CreateProduct(user *model.User, request *entity.AddSellerProductRequest) (*entity.SellerProduct, error) {
	// check user verified
	if user.Status != _const.UserStatusVerified {
		return nil, _error.New(_const.UserUnverified, "unverified user")
	}

	// check store exist and create
	store, err := u.storeRepo.FirstStore(store_repository.StoreFilter{
		StoreId: request.StoreId,
		UserId:  user.Id,
	})

	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, _error.New(_const.StoreNotFound, "store not found")
		}
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}

	if store.UserId != user.Id {
		return nil, _error.New(_const.StoreWrongOwner, "wrong store owner")
	}

	// check category exist
	category, err := u.categoryRepo.First(request.CategoryId)

	if err != nil {
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}

	if category == nil {
		return nil, _error.New(_const.CategoryNotFound, "category not found")
	}

	// create product
	product, err := u.CreateProductModel(user, request)
	if err != nil {
		return nil, err
	}

	// create stock of product
	storeProduct, err := u.CreateStoreProduct(store, product, request)
	if err != nil {
		return nil, err
	}

	err = u.ChangeStock(storeProduct.Id, storeProduct.Stock, storeProduct.Stock, "Số lượng khởi tạo lúc tạo sản phẩm", 0)
	if err != nil {
		return nil, err
	}

	u.UpdateStoreCategory(store, product.CategoryId)
	u.UpdateStoreTotalProducts(store)

	// find product for user
	createdProduct, err := u.productRepo.FindSellerProduct(&product_repository.ProductFilter{
		ProductId: product.Id,
	})

	if err != nil {
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}

	return &createdProduct[0], nil
}

func (u *useCase) UpdateStoreCategory(store *model.Store, catId int64) {
	if !util.IsInArray(catId, store.Category) {
		_ = u.storeRepo.UpdateStore(&model.Store{
			Id:       store.Id,
			Category: store.Category,
		})
	}
}

func (u *useCase) UpdateStoreTotalProducts(store *model.Store) {
	_ = u.storeRepo.UpdateStoreTotalProducts(store.Id)
}

func (u *useCase) UpdateProduct(user *model.User, productId int64, request *entity.UpdateSellerProductRequest) error {
	var product *model.Product
	var store *model.Store
	var wg sync.WaitGroup

	wg.Add(2)
	go func() {
		defer wg.Done()
		product, _ = u.productRepo.FirstProduct(product_repository.ProductFilter{
			ProductId: productId,
		})
	}()
	go func() {
		defer wg.Done()
		store, _ = u.storeRepo.FirstStore(store_repository.StoreFilter{
			StoreId: request.StoreId,
		})
	}()
	wg.Wait()

	if product == nil {
		return _error.New(_const.ProductNotFound, "product not found")
	}

	//if product.UserId != user.Id {
	//	return _error.New(_const.ProductWrongOwner, "you don't have permission to edit this product")
	//}

	if product.Status == _const.ProductStatusDeleted {
		return _error.New(_const.ProductNotFound, "product deleted")
	}

	if product.Status == _const.ProductStatusViolated {
		return _error.New(_const.ProductViolated, "product violated")
	}

	storeProduct, _ := u.productRepo.FirstStoreProduct(product_repository.ProductFilter{
		ProductId: product.Id,
		StoreId:   store.Id,
	})

	if storeProduct == nil {
		return _error.New(_const.ProductNotFound, "product not found")
	}

	images, _ := json.Marshal(request.Images)
	stockChange := request.Stock - storeProduct.Stock

	if err := u.productRepo.UpdateProduct(product.Id, map[string]interface{}{
		"name":                    request.Name,
		"category_id":             request.CategoryId,
		"thumbnail":               request.Thumbnail,
		"images":                  string(images),
		"unit":                    request.Unit,
		"description":             request.Description,
		"is_quote_after_ordering": request.IsQuoteAfterOrdering,
	}); err != nil {
		return _error.New(_const.InternalServerErr, err.Error())
	}

	if err := u.productRepo.UpdateStoreProduct(storeProduct.Id, &model.StoreProduct{
		Stock:              request.Stock,
		Price:              request.Price,
		DeliveryType:       request.DeliveryType,
		DeliveryCommitTime: request.DeliveryCommitTime,
	}); err != nil {
		return _error.New(_const.InternalServerErr, err.Error())
	}

	if stockChange != 0 {
		err := u.ChangeStock(storeProduct.Id, storeProduct.Stock, stockChange, fmt.Sprintf("cập nhật số lượng ngày %v", time.Now()), 0)
		if err != nil {
			return err
		}
	}

	u.UpdateStoreCategory(store, product.CategoryId)
	u.UpdateStoreTotalProducts(store)

	return nil
}

func (u *useCase) DeleteProduct(user *model.User, productId int64) error {
	if productId < 1 {
		return _error.New(_const.StatusBadRequest, "invalid product id")
	}

	product, _ := u.productRepo.FirstProduct(product_repository.ProductFilter{
		ProductId: productId,
	})

	if product == nil {
		return _error.New(_const.ProductNotFound, "product not found")
	}
	//
	//if product.UserId != user.Id {
	//	return _error.New(_const.ProductWrongOwner, "you don't have permission to edit this product")
	//}

	if product.Status == _const.ProductStatusDeleted {
		return _error.New(_const.ProductNotFound, "product deleted")
	}

	if product.Status == _const.ProductStatusViolated {
		return _error.New(_const.ProductViolated, "product violated")
	}

	err := u.productRepo.UpdateProduct(productId, map[string]interface{}{
		"status": _const.ProductStatusDeleted,
	})

	if err != nil {
		return _error.New(_const.InternalServerErr, err.Error())
	}

	return nil
}

func (u *useCase) GetSellerProduct(user *model.User, productId int64) (*entity.SellerProduct, error) {
	products, err := u.productRepo.FindSellerProduct(&product_repository.ProductFilter{
		UserId:    user.Id,
		ProductId: productId,
	})
	if err != nil {
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}
	return &products[0], nil
}

func (u *useCase) GetSellerProducts(user *model.User, filter *product_repository.ProductFilter) ([]entity.SellerProduct, error) {
	filter.SellerId = user.Id
	products, err := u.productRepo.FindSellerProduct(filter)
	if err != nil {
		return nil, _error.New(_const.InternalServerErr, err.Error())
	}
	return products, nil
}
