package orderman

import (
	"strings"
	"time"

	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	"git.rosy.net.cn/jx-callback/business/model"
	"git.rosy.net.cn/jx-callback/business/model/dao"
	"git.rosy.net.cn/jx-callback/business/partner"
	"git.rosy.net.cn/jx-callback/globals"
	"github.com/astaxie/beego/client/orm"
)

func (c *OrderManager) LoadAfsOrder(vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
	return c.loadAfsOrder(dao.GetDB(), vendorAfsOrderID, vendorID)
}

func (c *OrderManager) loadAfsOrder(db *dao.DaoDB, vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
	afsOrder = &model.AfsOrder{
		AfsOrderID: vendorAfsOrderID,
		VendorID:   vendorID,
	}
	if err = dao.GetEntity(db, afsOrder, "AfsOrderID", "VendorID"); err != nil {
		afsOrder = nil
	}
	return afsOrder, err
}

func (c *OrderManager) OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
	return c.onAfsOrderNew(afsOrder, orderStatus, true)
}

func (c *OrderManager) OnAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
	return c.onAfsOrderNew(afsOrder, orderStatus, false)
}

func (c *OrderManager) onAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus, isAdjust bool) (err error) {
	db := dao.GetDB()
	c.setAfsOrderID(db, orderStatus)
	if afsOrder.AfsOrderID == "" {
		afsOrder.AfsOrderID = orderStatus.VendorOrderID
	}
	if afsOrder.VendorStatus == "" {
		afsOrder.VendorStatus = orderStatus.VendorStatus
	}
	if afsOrder.Status == model.OrderStatusUnknown {
		afsOrder.Status = orderStatus.Status
	}
	if order, _ := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
		if order.ConsigneeMobile2 == "" {
			if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
				if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID, order.VendorStoreID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
					order.ConsigneeMobile = order2.ConsigneeMobile
					c.UpdateOrderFields(order, []string{"ConsigneeMobile"})
				}
			}
		}
	}
	//
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil || err != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()

	isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
	if err != nil || (isDuplicated && orderStatus.VendorID != model.VendorIDJX) {
		if err == nil {
			dao.Commit(db, txDB)
		}
		return err
	}
	existAfsOrder, err := c.loadAfsOrder(db, afsOrder.AfsOrderID, afsOrder.VendorID)
	if err != nil {
		if !dao.IsNoRowsError(err) {
			return err
		}
	}
	if existAfsOrder != nil {
		if existAfsOrder.Status < model.AfsOrderStatusFinished {
			// todo 可能导致状态回绕
			existAfsOrder.Status = afsOrder.Status
			existAfsOrder.VendorStatus = afsOrder.VendorStatus
			if _, err = dao.UpdateEntity(db, existAfsOrder, "Status", "VendorStatus", "AfsFinishedAt"); err != nil {
				return err
			}
			afsOrder = existAfsOrder
		}

	} else {
		// 全退都要先全删除再建
		if afsOrder.RefundType == model.AfsTypeFullRefund {
			isAdjust = true
		}
		if err = c.SaveAfsOrder(db, afsOrder, isAdjust); err != nil {
			return err
		}
	}

	dao.Commit(db, txDB)
	scheduler.CurrentScheduler.OnAfsOrderNew(afsOrder, false)
	return err
}

func (c *OrderManager) SaveAfsOrder(db *dao.DaoDB, afsOrder *model.AfsOrder, isDeleteFirst bool) (err error) {
	if db == nil {
		db = dao.GetDB()
	}
	if err = c.updateAfsOrderOtherInfo(db, afsOrder); err != nil {
		return err
	}
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil || err != nil {
			dao.Rollback(db, txDB)
			if r != nil {
				panic(r)
			}
		}
	}()
	if isDeleteFirst {
		err = utils.CallFuncLogError(func() error {
			_, err = dao.DeleteEntity(db, afsOrder, "VendorOrderID", "VendorID")
			return err
		}, "SaveAfsOrder delete AfsOrder, afsOrderID:%s", afsOrder.AfsOrderID)
		if err != nil {
			return err
		}
		err = utils.CallFuncLogError(func() error {
			_, err = dao.DeleteEntity(db, &model.OrderSkuFinancial{
				VendorOrderID: afsOrder.VendorOrderID,
				VendorID:      afsOrder.VendorID,
				IsAfsOrder:    1,
			}, "VendorOrderID", "VendorID", "IsAfsOrder")
			return err
		}, "SaveAfsOrder delete OrderSkuFinancial, afsOrderID:%s", afsOrder.AfsOrderID)
		if err != nil {
			return err
		}
	}
	// 平台结算扣除汇总--平台补贴，售后产生运费，平台收包装费，同城运费、、、
	deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
	afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
	// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
	if err = dao.CreateEntity(db, afsOrder); err != nil {
		return err
	}

	// 京西结算扣除汇总，先不作计算,计算单条sku最终扣款金额（+该条sku承担的平台结算扣除金额）
	for _, orderSku := range afsOrder.Skus[1:] {
		orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
			utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
		afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
		if err = dao.CreateEntity(db, orderSku); err != nil {
			return err
		}
	}
	if len(afsOrder.Skus) > 0 {
		orderSku := afsOrder.Skus[0]
		orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
		if err = dao.CreateEntity(db, orderSku); err != nil {
			return err
		}
	} else {
		globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
	}
	dao.Commit(db, txDB)
	return err
}

func (c *OrderManager) OnAfsOrderStatusChanged(orderStatus *model.OrderStatus) (err error) {
	db := dao.GetDB()
	c.setAfsOrderID(db, orderStatus)
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	isDuplicated, afsOrder, err := c.addAfsOrderStatus(db, orderStatus)
	if err != nil || isDuplicated {
		if err == nil {
			dao.Commit(db, txDB)
		} else {
			dao.Rollback(db, txDB)
		}
		return err
	}
	dao.Commit(db, txDB)
	scheduler.CurrentScheduler.OnAfsOrderStatusChanged(afsOrder, orderStatus, false)
	return err
}

func (c *OrderManager) addAfsOrderStatus(db *dao.DaoDB, orderStatus *model.OrderStatus) (isDuplicated bool, order *model.AfsOrder, err error) {
	if db == nil {
		db = dao.GetDB()
	}
	isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
	//if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
	if err == nil && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
		order = &model.AfsOrder{
			AfsOrderID: orderStatus.VendorOrderID,
			VendorID:   orderStatus.VendorID,
		}
		if err = db.Db.ReadForUpdate(order, "AfsOrderID", "VendorID"); err == nil {
			if orderStatus.Status > model.OrderStatusUnknown { // todo 要求status不能回绕
				order.VendorStatus = orderStatus.VendorStatus
				order.Status = orderStatus.Status
				updateFields := []string{
					"VendorStatus",
					"Status",
				}
				if orderStatus.VendorID == model.VendorIDDD {
					order.Flag = 0
					if strings.Contains(orderStatus.VendorStatus, "cancel_refund_afsOrder") {
						order.Flag = 3
					}
					updateFields = append(updateFields, "Flag")
				}
				if model.IsAfsOrderFinalStatus(orderStatus.Status) || orderStatus.Status == model.AfsOrderStatusNew {
					order.AfsFinishedAt = orderStatus.StatusTime
					if utils.IsTimeZero(order.AfsFinishedAt) {
						order.AfsFinishedAt = time.Now()
					}
					updateFields = append(updateFields, "AfsFinishedAt")
					if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
						if orderAfsInfo, err := handler.GetOrderAfsInfo(nil, order.VendorOrderID, order.AfsOrderID); err == nil && orderAfsInfo.AfsTotalShopMoney != 0 {
							order.AfsTotalShopMoney = orderAfsInfo.AfsTotalShopMoney
							updateFields = append(updateFields, "AfsTotalShopMoney")
						}
					}
				}
				_, err = dao.UpdateEntity(db, order, updateFields...)
				//utils.CallFuncLogError(func() error {
				//	_, err = dao.UpdateEntity(db, order, updateFields...)
				//	return err
				//}, "addAfsOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
			} else {
				isDuplicated = true
			}
		} else {
			// 这是发现有部分订单已经完成,但是没有完成时间影响到导出结果错误
			if model.IsAfsOrderFinalStatus(orderStatus.Status) || orderStatus.Status == model.AfsOrderStatusNew && order.VendorID == model.VendorIDMTWM {
				if afsOrderObj, _ := partner.CurOrderManager.LoadAfsOrder(orderStatus.VendorOrderID, orderStatus.VendorID); afsOrderObj != nil {
					afsOrderObj.AfsFinishedAt = time.Now()
					afsOrderObj.Status = orderStatus.Status
					dao.UpdateEntity(db, afsOrderObj, "AfsFinishedAt", "Status")
				}
			}
			if dao.IsNoRowsError(err) { // todo 消息错序
				err = nil
			} else {
				globals.SugarLogger.Warnf("addAfsOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
			}
		}
	}
	return isDuplicated, order, err
}

func (c *OrderManager) updateAfsOrderSkuOtherInfo(db *dao.DaoDB, order *model.AfsOrder) (err error) {
	jxStoreID := jxutils.GetSaleStoreIDFromAfsOrder(order)
	opNumStr := "2"
	if jxStoreID == 0 {
		return nil
	}
	orderSkus := order.Skus
	var vendorSkuIDs []string
	skuIDMap := make(map[int]int)
	for _, v := range orderSkus {
		if v.VendorSkuID != "" {
			vendorSkuIDs = append(vendorSkuIDs, v.VendorSkuID)
		}

		if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 {
			skuIDMap[skuID] = 1
		}
	}
	if len(vendorSkuIDs) > 0 {
		var vendorStoreID string
		if order.VendorID == model.VendorIDJDShop {
			vendorStoreID = model.JdShopMainVendorStoreID
		} else {
			vendorStoreID = order.VendorStoreID
		}
		l, err := dao.GetStoreSkuPriceAndWeight(db, vendorStoreID, order.VendorID, vendorSkuIDs)
		if err != nil {
			return err
		}
		skumapper := storeSkuPriceAndWeight2Map(l)

		var actStoreSkuMap *jxutils.ActStoreSkuMap
		if len(skuIDMap) > 0 {
			if order2, err2 := c.LoadOrder(order.VendorOrderID, order.VendorID); err2 == nil {
				actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order2.OrderCreatedAt, order2.OrderCreatedAt)
				if err != nil {
					return err
				}
				actStoreSkuMap = jxutils.NewActStoreSkuMap(actStoreSkuList, false)
			}
		}
		for _, v := range orderSkus {
			v.AfsOrderID = order.AfsOrderID
			v.VendorID = order.VendorID
			v.VendorOrderID = order.VendorOrderID
			v.IsAfsOrder = 1
			v.VendorStoreID = order.VendorStoreID
			v.StoreID = order.StoreID
			v.JxStoreID = jxStoreID

			intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
			if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
				skuBindInfo := skumapper[v.VendorSkuID]
				if skuBindInfo == nil {
					globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]%s订单sku找不到门店价格（或商品映射），orderID:%s, StoreID:%d, VendorSkuID:%s, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.VendorSkuID, v)
				} else {
					v.JxSkuID = skuBindInfo.SkuID
					v.ShopPrice = int64(skuBindInfo.Price)
				}
			}
			if actStoreSkuMap != nil {
				if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 && v.StoreSubName != "" {
					if actStoreSku := actStoreSkuMap.GetActStoreSku(jxStoreID, skuID, order.VendorID); actStoreSku != nil {
						v.StoreSubID = actStoreSku.ActID
					}
				}
			}
		}
	}
	return nil
}

func (c *OrderManager) updateAfsOrderOtherInfo(db *dao.DaoDB, afsOrder *model.AfsOrder) (err error) {
	if afsOrder.VendorStoreID != "" {
		if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, afsOrder.VendorStoreID, 0, ""); err == nil {
			afsOrder.JxStoreID = storeDetail.Store.ID
		}
	}
	order, err2 := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
	if afsOrder.StoreID == 0 && afsOrder.JxStoreID == 0 {
		if err2 == nil {
			afsOrder.JxStoreID = order.JxStoreID
			if afsOrder.StoreID == 0 {
				afsOrder.StoreID = order.StoreID
			}
			if afsOrder.VendorStoreID == "" {
				afsOrder.VendorStoreID = order.VendorStoreID
			}
		}
	}
	if err == nil {
		if handler := partner.GetPurchaseOrderHandlerFromVendorID(afsOrder.VendorID); handler != nil {
			if orderAfsInfo, err := handler.GetOrderAfsInfo(nil, afsOrder.VendorOrderID, afsOrder.AfsOrderID); err == nil && orderAfsInfo.AfsTotalShopMoney != 0 {
				afsOrder.AfsTotalShopMoney = orderAfsInfo.AfsTotalShopMoney
			}
		}
		if err = c.updateAfsOrderSkuOtherInfo(db, afsOrder); err == nil {
			jxutils.RefreshAfsOrderSkuRelated(afsOrder)
			if afsOrder.RefundType == model.AfsTypeFullRefund && afsOrder.VendorID == model.VendorIDJX && order.DeliveryType != model.OrderDeliveryTypeSelfTake {
				afsOrder.SkuUserMoney = order.ActualPayPrice
			}
		}
	}
	return err
}

func (c *OrderManager) UpdateAfsOrderFields(afsOrder *model.AfsOrder, fieldList []string) (err error) {
	db := orm.NewOrm()
	utils.CallFuncLogError(func() error {
		_, err = db.Update(afsOrder, fieldList...)
		return err
	}, "UpdateAfsOrderFields orderID:%s failed with error:%v", afsOrder.VendorOrderID, err)
	return err
}

func (c *OrderManager) setAfsOrderID(db *dao.DaoDB, orderStatus *model.OrderStatus) {
	if dao.IsVendorThingIDEmpty(orderStatus.VendorOrderID) {
		index := 1
		if afsOrderList, err2 := dao.GetAfsOrders(db, orderStatus.RefVendorID, orderStatus.RefVendorOrderID, ""); err2 == nil {
			if len(afsOrderList) > 0 {
				list := strings.Split(afsOrderList[0].AfsOrderID, "-")
				if len(list) > 1 {
					index = int(utils.Str2Int64WithDefault(list[1], 0))
					//if afsOrderList[0].Status >= model.AfsOrderStatusFinished {
					index++
					//}
				}
			}
		} else {
			globals.SugarLogger.Warnf("setAfsOrderID err2:%v", err2)
		}
		orderStatus.VendorOrderID = composeAfsOrderID(orderStatus.RefVendorOrderID, index)
	}
}

func composeAfsOrderID(vendorOrderID string, index int) (afsOrderID string) {
	return strings.Join([]string{
		vendorOrderID,
		utils.Int2Str(index),
	}, "-")
}

func (c *OrderManager) CreateAfsOrderFromOrder(vendorOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
	order, err := c.LoadOrder(vendorOrderID, vendorID)
	if err == nil {
		afsOrder = &model.AfsOrder{
			VendorID:      vendorID,
			VendorOrderID: vendorOrderID,
			JxStoreID:     order.JxStoreID,
			VendorStoreID: order.VendorStoreID,
			StoreID:       order.StoreID,
			VendorOrgCode: order.VendorOrgCode,
		}
	} else {
		return nil, err
	}

	for _, sku := range order.Skus {
		orderSkuFinancial := &model.OrderSkuFinancial{
			VendorID:         sku.VendorID,
			VendorOrderID:    sku.VendorOrderID,
			VendorSubOrderID: sku.VendorSubOrderID,
			// OrderFinancialID: sku.VendorOrderID,
			// ConfirmTime:      afsOrder.AfsCreateAt,
			VendorStoreID: afsOrder.VendorStoreID,
			StoreID:       afsOrder.StoreID,
			JxStoreID:     afsOrder.JxStoreID,
			VendorSkuID:   sku.VendorSkuID,
			SkuID:         sku.SkuID,
			PromotionType: sku.PromotionType,
			Name:          sku.SkuName,
			ShopPrice:     sku.ShopPrice,
			SalePrice:     sku.SalePrice,
			Count:         sku.Count,
			// UserMoney:      sku.UserMoney,
			// PmSubsidyMoney: sku.PmSubsidyMoney,
			IsAfsOrder: 1,
		}
		afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
	}
	return afsOrder, nil
}
