package biz

import (
	"context"
	"errors"
	"fmt"
	"gorm.io/gorm"
	"strconv"
	"time"

	//"time"

	"github.guxuan/haibei/internal/mods/app/dal"
	//"github.guxuan/haibei/internal/mods/app/schema"
	activityDal "github.guxuan/haibei/internal/mods/activity/dal"
	activitySchema "github.guxuan/haibei/internal/mods/activity/schema"
	commonDal "github.guxuan/haibei/internal/mods/common/dal"
	commonSchema "github.guxuan/haibei/internal/mods/common/schema"
	customerDal "github.guxuan/haibei/internal/mods/customer/dal"
	customerSchema "github.guxuan/haibei/internal/mods/customer/schema"
	productDal "github.guxuan/haibei/internal/mods/product/dal"
	productSchema "github.guxuan/haibei/internal/mods/product/schema"
	//"github.guxuan/haibei/pkg/errors"
	"github.guxuan/haibei/pkg/util"
)

// Defining the `App` business logic.
type App struct {
	DB                 *gorm.DB
	Trans              *util.Trans
	AppDAL             *dal.App
	BannerDal          *commonDal.Banner
	NoticeDal          *commonDal.Notice
	ProductDal         *productDal.Product
	ProductCategoryDal *productDal.ProductCategory
	ProductOrderDal    *customerDal.ProductOrder
	ActivityDal        *activityDal.Activity
	ActivityDetailDal  *activityDal.ActivityDetail
	QuestionnaireDal   *activityDal.Questionnaire
	QeustionDetailDal  *activityDal.QeustionDetail
	CustomerDal        *customerDal.Customer
	BalanceDal         *customerDal.Balance
}

func (a *App) QueryBannerList(ctx context.Context, areaId uint) (*[]commonSchema.Banner, error) {
	query := commonDal.GetBannerDB(ctx, a.DB)
	if areaId > 0 {
		query.Where("area_id = ?", areaId)
	}
	var list []commonSchema.Banner
	query.Order("sequence DESC").Limit(3).Find(&list)
	return &list, nil
}
func (a *App) QueryNoticeList(ctx context.Context, areaId uint) (*[]commonSchema.Notice, error) {
	query := commonDal.GetNoticeDB(ctx, a.DB)
	if areaId > 0 {
		query.Where("area_id = ?", areaId)
	}
	var list []commonSchema.Notice
	query.Order("sequence DESC").Limit(6).Find(&list)
	return &list, nil
}

func (a *App) QueryHomeProductList(ctx context.Context, isHot bool, areaId uint) (*[]productSchema.Product, error) {
	query := productDal.GetProductDB(ctx, a.DB).Preload("Category").Where("status = ?", "enabled")
	query.Where("area_id = ?", areaId)
	if isHot {
		query.Where("is_hot = ?", 1)
	}
	var list []productSchema.Product
	query.Order("createAt DESC").Find(&list)
	return &list, nil
}

func (a *App) QueryProductDetails(ctx context.Context, id uint) (productSchema.Product, error) {
	query := productDal.GetProductDB(ctx, a.DB).Preload("Category").Where("id = ?", id)

	var info productSchema.Product
	query.First(&info)
	return info, nil
}

func (a *App) QueryHomeActivityList(ctx context.Context, areaId uint) (activitySchema.Activities, error) {
	query := activityDal.GetActivityDB(ctx, a.DB).Where("status = ?", "enabled")
	query.Where("area_id = ?", areaId)
	var list activitySchema.Activities
	query.Order("createAt DESC").Find(list)
	return list, nil

}

func (a *App) QueryActivityDetails(ctx context.Context, customerId, id uint) (activitySchema.Activity, *activitySchema.ActivityDetail, error) {
	query := activityDal.GetActivityDB(ctx, a.DB).Where("id = ?", id)
	var info activitySchema.Activity
	query.First(&info)
	result, _ := a.ActivityDetailDal.GetByCustomerIDAndActivityID(ctx, customerId, id)
	return info, result, nil
}

func (a *App) QueryHomeQuestionsList(ctx context.Context, areaId uint) (activitySchema.Questionnaires, error) {
	query := activityDal.GetQuestionnaireDB(ctx, a.DB).Where("status = ?", "enabled")
	query.Where("area_id = ?", areaId)
	var list activitySchema.Questionnaires
	query.Order("createAt DESC").Find(list)
	return list, nil

}

func (a *App) QueryQuestionsDetails(ctx context.Context, customerId, id uint) (activitySchema.Questionnaire, *activitySchema.QeustionDetail, error) {
	query := activityDal.GetQuestionnaireDB(ctx, a.DB).Where("id = ?", id)
	var info activitySchema.Questionnaire
	query.First(&info)
	result, _ := a.QeustionDetailDal.GetByCustomerIDAndActivityID(ctx, customerId, id)
	return info, result, nil
}

func (a *App) AddProductToCustomer(ctx context.Context, customerID, productID, num uint) error {
	customer, err2 := a.CustomerDal.Get(ctx, customerID, customerSchema.CustomerQueryOptions{})
	if err2 != nil {
		return errors.New("用户未找到")
	}

	product, err := a.ProductDal.Get(ctx, productID, productSchema.ProductQueryOptions{})
	if err != nil {
		return errors.New("商品未找到")
	}
	if product.Stock < int(num) {
		return errors.New("商品库存不足")
	}
	if product.Status != "enabled" {
		return errors.New("商品状态不可用")
	}
	if product.ExpireAt.Before(time.Now()) {
		return errors.New("商品已过期")
	}
	if customer.Balance < product.Price*int(num) {
		return errors.New("积分不足")
	}
	info, err := a.ProductOrderDal.ExistsByCustomerID(ctx, customerID, productID)
	if err != nil {
		return errors.New("系统繁忙，请稍后再试！")
	}
	if info != nil && len(*info) >= product.MaxNum {
		return errors.New("兑换数量已达到上限")
	}

	orderInfo := customerSchema.ProductOrder{
		CustomerID: customerID,
		ProductID:  productID,
		MentorID:   customer.MentorID,
		Status:     "UNCHECK",
	}
	return a.Trans.Exec(ctx, func(ctx context.Context) error {
		//创建商品订单
		err = a.ProductOrderDal.Create(ctx, &orderInfo)
		if err != nil {
			return errors.New("系统繁忙，请稍后再试！")
		}
		//修改库存
		product.Stock--
		err = a.ProductDal.Update(ctx, product)
		if err != nil {
			return errors.New("系统繁忙，请稍后再试！")
		}
		//积分变动
		oldBalance := customer.Balance
		change := product.Price * int(num)
		newBalance := oldBalance - change
		customer.Balance = newBalance
		err = a.CustomerDal.Update(ctx, customer)
		if err != nil {
			return errors.New("系统繁忙，请稍后再试！")
		}
		var record = customerSchema.Balance{
			CustomerID: customerID,
			Before:     oldBalance,
			After:      newBalance,
			Change:     -change,
			Reason:     fmt.Sprintf("用户通过小程序兑换商品-%s", product.Name),
			Typer:      "兑换商品",
			OperatorID: productID,
			CreatorID:  "",
		}
		err = a.BalanceDal.Create(ctx, &record)
		if err != nil {
			return errors.New("系统繁忙，请稍后再试！")
		}
		return nil
	})

}

func (a *App) RegisterActivity(ctx context.Context, customerID, activityID uint) error {
	return nil
}

func (a *App) RegisterQuestion(ctx context.Context, customerID, questionID uint, questionBody *[]activitySchema.QuestionDetailTable) error {
	return nil
}

func (a *App) GetLoginUid(ctx context.Context) (uint, error) {
	userID := util.FromUserID(ctx)
	u64, err := strconv.ParseUint(fmt.Sprintf("%v", userID), 10, 64)
	if err != nil {
		fmt.Println("转换错误:", err)
		return 0, errors.New("登录id获取失败")
	}
	return uint(u64), nil
}
