package course

import (
	"errors"
	"spaceofcheng/services/models"
	"spaceofcheng/services/models/course"
	"spaceofcheng/services/models/model"
	"spaceofcheng/services/utils"
	"strconv"
	"time"

	"github.com/yl10/kit/guid"
)

// Orders 下单
func (s *CourseServ) Orders(
	couseOrder *model.TaCourseOrders,
	coupons []model.TaCourseOrdersCoupon,
) error {
	org := s.ctx.Get("org").(model.SysOrg)
	cust := s.ctx.Get("customer").(model.TaCustomer)

	// 校验人员
	if cust.CustomerId != couseOrder.CustomerId {
		return errors.New("下单人非当前人员")
	}
	if cust.UserId != "" {
		// 内部人员
		// 如果是内部人员购买或者兑换课程, 卡券或者城币就从内部人员自己的账户走
		couseOrder.PayType = models.CONSUME_INNER
	} else {
		// 默认是卡券支付
		couseOrder.PayType = models.CONSUME_COUPON
	}

	// 校验案场
	caseID := couseOrder.CaseId
	if err := utils.NewAuthEngine(s.ctx).CheckCase(caseID); err != nil {
		return err
	}

	// 校验课程
	course, err := s.validCourse(couseOrder)
	if err != nil {
		return err
	}
	if course.CourseDetail == nil || len(course.CourseDetail) > 0 {
		return errors.New("定单课程尚未排课, 不能下单")
	}

	if coupons != nil && len(coupons) > 0 {
		// 校验卡券, 同时进行卡券的注销或者已使用的更新操作
		// TODO
	}

	// 课程价格, 即为订单价格
	couseOrder.Price = course.Price
	couseOrder.ActualAmount = course.Price
	couseOrder.CourseName = course.CourseName
	couseOrder.CourseNum = course.CourseNum
	couseOrder.OrgId = org.OrgId
	if cust.Name != "" {
		couseOrder.CustomerName = cust.Name
	} else {
		couseOrder.CustomerName = cust.CustomerName
	}

	// 校验金额
	if err := s.validBillCharges(couseOrder, coupons); err != nil {
		return err
	}

	// 入库
	if err := s.dao.SaveCourseOrder(couseOrder); err != nil {
		utils.LogError("课程下单失败: " + err.Error())
		return errors.New("下单失败, 请重试")
	}

	// 实际支付
	actualAmount, _ := strconv.ParseFloat(couseOrder.ActualAmount, 64)

	// 用户账户
	if actualAmount > 0 {
		couseOrder.PayType = models.CONSUME_COINCHG
		account, err := s.custDAO.GetAccountByCust(cust.CustomerId)
		if err != nil {
			utils.LogError("查询用户账户信息出错: " + err.Error())
			return errors.New("查询用户账户信息出错")
		}
		accMoney, _ := strconv.ParseFloat(account.Amount, 64)

		if actualAmount > accMoney {
			return errors.New("账户余额不足")
		}
	}

	return nil
}

// validCourse 校验课程
func (s *CourseServ) validCourse(order *model.TaCourseOrders) (*course.CourseDetail, error) {
	if order.CourseId == "" {
		return nil, errors.New("没有获取到下单课程")
	}

	custCourse, err := s.dao.GetCourseOfCustomer(order.CustomerId, order.CourseId)
	if err != nil {
		utils.LogError("校验用户课程失败: " + err.Error())
		return nil, errors.New("校验用户课程失败")
	}

	if custCourse != nil && custCourse.CustomerCourseId != "" {
		if custCourse.Status != models.STATUS_DEL {
			return nil, errors.New("用户已经拥有该课程, 不需要再次下单")
		}
	}

	// 课程
	course, err := s.dao.GetCourseInfo(order.CourseId)
	if err != nil {
		utils.LogError("获取课程信息失败: " + err.Error())
		return nil, errors.New("获取课程信息失败")
	}

	if course.Status != models.STATUS_NORMAL {
		return nil, errors.New("课程状态不正确, 不能购买或者兑换")
	}

	return course, nil
}

// validCustomer 校验客户
func (s *CourseServ) validCustomer(custID string) (*model.TaCustomer, error) {
	if custID == "" {
		return nil, errors.New("没有获取到下单人员")
	}

	cust, err := s.custDAO.GetCustomerByID(custID)
	if err != nil {
		utils.LogError("查询下单人出错: " + err.Error())
		return nil, errors.New("验证下单人出错")
	}

	if cust.Status != models.STATUS_NORMAL {
		return nil, errors.New("下单人状态不正确, 不能下单")
	}

	return cust, nil
}

// validBillCharges 校验各种金额, 数量等
func (s *CourseServ) validBillCharges(
	couseOrder *model.TaCourseOrders,
	coupons []model.TaCourseOrdersCoupon,
) error {
	orderCost, _ := strconv.ParseFloat(couseOrder.Price, 64)
	// 算法开始, 实际支付 == 订单金额
	actualAmount := orderCost
	// 优惠金额是 0
	couponAmount := float64(0.0)

	couseOrder.ActualAmount = strconv.FormatFloat(actualAmount, 'f', -1, 64)
	couseOrder.CouponAmount = strconv.FormatFloat(couponAmount, 'f', -1, 64)

	// 如果不是使用的卡券
	if coupons == nil || len(coupons) == 0 {
		return nil
	}

	// 目前的业务是, 购买课程只能使用一张卡券
	// 这里使用的是数组, 相当于做一个拓展
	for _, coupon := range coupons {
		// TODO 从卡券字典中获取价格
		// 目前是前端传过来的
		dedCharge, err := strconv.ParseFloat(coupon.UsedAmount, 64)
		if err != nil {
			utils.LogError("获取卡券抵用金额失败: " + err.Error())
			return errors.New("获取卡券抵用金额错误")
		}

		if dedCharge < 0 {
			return errors.New("卡券抵用金额不能为负值")
		}

		couponAmount += dedCharge
	}

	// 如果优惠券金额 > 订单金额
	if couponAmount > orderCost {
		couponAmount = orderCost
		actualAmount = float64(0)
	} else {
		actualAmount = orderCost - couponAmount
	}

	couseOrder.ActualAmount = strconv.FormatFloat(actualAmount, 'f', -1, 64)
	couseOrder.CouponAmount = strconv.FormatFloat(couponAmount, 'f', -1, 64)
	return nil
}

// saveCustomerPayRec 保存账户消费流水
func (s *CourseServ) saveCustomerPayRec(account *model.TaCustomerAccount, info *model.TaCourseOrders) error {
	accBill := new(model.TaAccountChange)
	accBill.AccountId = account.AccountId
	accBill.Amount = info.ActualAmount
	accBill.CaseId = info.CaseId
	accBill.ChangeSource = models.ACCSOURCE_COURSE_ORDERS
	accBill.ChangeType = models.CONSUME_COINCHG
	accBill.CustomerId = info.CustomerId
	accBill.CustomerName = info.CustomerName
	accBill.FloatType = models.ACCOUNT_SPENT
	accBill.SourceId = info.OrdersId
	accBill.SourceName = ""

	return s.custDAO.InsertAccountRecords(accBill)
}

// SaveOrder 保存订单明细
func (s *CourseServ) SaveOrder(order *model.TaCourseOrders, coupons []model.TaCourseOrdersCoupon, course *course.CourseDetail) error {
	// 订单信息
	if err := s.dao.SaveCourseOrder(order); err != nil {
		utils.LogError("课程下单失败: " + err.Error())
		return errors.New("下单失败, 请重试")
	}

	// 默认城币购买
	courseObtaimType := models.COURSE_GETBY_COINCHG
	srcID := ""
	if coupons != nil && len(coupons) > 0 {
		for _, c := range coupons {
			if c.CouponType == models.COURSE_COUPON_CARD {
				courseObtaimType = models.COURSE_GETBY_CARD
			} else if c.CouponType == models.COURSE_COUPON_COUPON {
				courseObtaimType = models.COURSE_GETBY_COUPON
			}

			srcID = c.CouponId
		}
	}

	// 我的课程信息
	custCourse := model.TaCustomerCourse{
		CourseId:         order.CourseId,
		CustomerId:       order.CustomerId,
		OrgId:            order.OrgId,
		CaseId:           order.CaseId,
		CourseName:       course.CourseName,
		Price:            course.Price,
		CourseNum:        course.CourseNum,
		JoinNum:          0,
		CreateDate:       time.Now().Local(),
		CourseObtaimType: courseObtaimType,
		SourceId:         srcID,
		IsDone:           models.BOOL_FALSE,
	}

	details := make([]model.TaCourseOrdersDetail, 0)
	custCourseDetails := make([]model.TaCustomerCourseDetail, 0)

	for _, subCourse := range course.CourseDetail {
		d1 := model.TaCourseOrdersDetail{
			OrdersDetailId: guid.NewGUIDString(),
			OrdersId:       order.OrdersId,
			CourseId:       course.CourseId,
			CourseDetailId: subCourse.DetailId,
			BeginDate:      subCourse.BeginDate,
			EndDate:        subCourse.EndDate,
		}
		details = append(details, d1)

		d2 := model.TaCustomerCourseDetail{
			CourseId:     course.CourseId,
			DetailId:     subCourse.DetailId,
			StartDate:    subCourse.BeginDate,
			EndDate:      subCourse.EndDate,
			VerifyStatus: models.VERIFY_USEABLE,
			CaseId:       order.CaseId,
		}
		custCourseDetails = append(custCourseDetails, d2)
	}

	if err := s.dao.SaveCourseOfCustomer(&custCourse, custCourseDetails); err != nil {
		utils.LogError("插入我的课程失败: " + err.Error())
		return errors.New("写入我的课程失败")
	}

	if err := s.dao.SaveCourseOrderDetail(details); err != nil {
		utils.LogError("插入课程订单详情: " + err.Error())
		return errors.New("写入课程订单详情失败")
	}

	return nil
}
