package svc

import (
	"applet/app/db"
	"applet/app/db/model"
	"applet/app/e"
	"applet/app/md"
	"applet/app/utils"
	"applet/app/utils/cache"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"strings"
	"time"
	"xorm.io/xorm"
)

func StoreOrderCate(c *gin.Context) {
	var cate = []map[string]string{
		{"name": "全部", "value": ""},
		{"name": "待付款", "value": "0"},
		{"name": "待提货", "value": "1"},
		{"name": "已完成", "value": "2"},
		{"name": "已取消", "value": "3"},
	}
	e.OutSuc(c, cate, nil)
	return
}
func GetDate(c *gin.Context, arg map[string]string) (time.Time, time.Time) {
	var stime, etime time.Time
	t := time.Now()
	if arg["type"] == "day" {
		stime = utils.TimeParseStd(arg["date"] + " 00:00:00")
		etime = time.Unix(stime.Unix()+86400, 0)
	}
	if arg["type"] == "month" {
		ex := strings.Split(arg["date"], "-")
		year := utils.StrToInt(ex[0])
		stime = time.Date(year, time.Month(utils.StrToInt(ex[1])-1), 1, 0, 0, 0, 0, t.Location())
		if utils.StrToInt(ex[1]) == 12 {
			year++
			ex[1] = "1"
		}
		etime = time.Date(year, time.Month(utils.StrToInt(ex[1])), 1, 0, 0, 0, 0, t.Location())
	}
	if arg["type"] == "year" {
		year := utils.StrToInt(arg["date"])
		stime = time.Date(year, time.Month(0), 1, 0, 0, 0, 0, t.Location())
		etime = time.Date(year+1, time.Month(0), 1, 0, 0, 0, 0, t.Location())
	}
	return stime, etime
}

func StoreOrderList(c *gin.Context) {
	var arg map[string]string
	if err := c.ShouldBindJSON(&arg); err != nil {
		e.OutErr(c, e.ERR_INVALID_ARGS, err)
		return
	}
	user := GetUser(c)
	arg["store_uid"] = utils.IntToStr(user.Info.Uid)
	if arg["type"] != "" && arg["date"] != "" {
		stime, etime := GetDate(c, arg)
		arg["start_time"] = stime.Format("2006-01-02 15:04:05")
		arg["end_time"] = etime.Format("2006-01-02 15:04:05")
	}
	data := db.GetOrderList(c, MasterDb(c), arg)
	var state = []string{"待付款", "待提货", "已完成", "已取消"}
	list := make([]map[string]interface{}, 0)
	if data != nil {
		scheme, host := ImageBucket(c)

		now := time.Now().Unix()
		for _, v := range *data {
			store := db.GetStoreIdEg(MasterDb(c), utils.IntToStr(v.StoreUid))
			info := db.GetOrderInfoAllEg(MasterDb(c), utils.Int64ToStr(v.Oid))
			downTime := "0"
			if v.State == 0 {
				downTime = utils.IntToStr(int(v.CreateAt.Unix() + 15*60 - now))
				if now > v.CreateAt.Unix()+15*60 {
					v.State = 3
				}
				if utils.StrToInt(downTime) < 0 {
					downTime = "0"
				}
			}
			storeName := ""
			if store != nil {
				storeName = store.Name
			}
			goodsInfo := make([]map[string]string, 0)
			if info != nil {
				for _, v1 := range *info {
					skuData := make([]md.Sku, 0)
					json.Unmarshal([]byte(v1.SkuInfo), &skuData)
					skuStr := ""
					for _, v2 := range skuData {
						if skuStr != "" {
							skuStr += ";"
						}
						skuStr += v2.Value
					}
					if skuStr != "" {
						skuStr = "(" + skuStr + ")"
					}
					tmp := map[string]string{
						"title": v1.Title + skuStr,
						"num":   utils.IntToStr(v1.Num),
						"img":   ImageFormatWithBucket(scheme, host, v1.Img),
					}
					goodsInfo = append(goodsInfo, tmp)
				}
			}
			user1, _ := db.UserFindByID(MasterDb(c), v.Uid)
			userProfile, _ := db.UserProfileFindByID(MasterDb(c), v.Uid)
			nickname := ""
			headImg := ""
			if userProfile != nil {
				headImg = userProfile.AvatarUrl
			}
			if user1 != nil {
				if user1.Nickname != user1.Phone {
					user1.Nickname += " " + user1.Phone
				}
				nickname = user1.Nickname
			}
			tmp := map[string]interface{}{
				"goods_info": goodsInfo,
				"oid":        utils.Int64ToStr(v.Oid),
				"label":      "自提",
				"state":      utils.IntToStr(v.State),
				"state_str":  state[v.State],
				"store_name": storeName,
				"coupon":     v.Coupon,
				"commission": v.Commission,
				"username":   nickname,
				"head_img":   headImg,
				"table_num":  v.TableNum,
				"amount":     v.Amount,
				"num":        utils.IntToStr(v.Num),
				"down_time":  downTime,
				"create_at":  v.CreateAt.Format("2006-01-02 15:04:05"),
				"pay_at":     "",
				"confirm_at": "",
			}
			if v.PayAt.IsZero() == false {
				tmp["pay_at"] = v.PayAt.Format("2006-01-02 15:04:05")
			}
			if v.ConfirmAt.IsZero() == false {
				tmp["confirm_at"] = v.ConfirmAt.Format("2006-01-02 15:04:05")
			} else {
				if v.IsNow == 1 {
					tmp["confirm_at"] = "立即提货"
				} else if v.Timer != "" {
					tmp["confirm_at"] = v.Timer
				}
			}
			if v.Type == 1 {
				tmp["label"] = "外卖"
			}
			list = append(list, tmp)
		}
	}
	e.OutSuc(c, list, nil)
	return
}
func StoreOrderDetail(c *gin.Context) {
	var arg map[string]string
	if err := c.ShouldBindJSON(&arg); err != nil {
		e.OutErr(c, e.ERR_INVALID_ARGS, err)
		return
	}
	data := db.GetOrderEg(MasterDb(c), arg["oid"])
	var state = []string{"待付款", "待提货", "已完成", "已取消"}
	now := time.Now().Unix()
	downTime := "0"
	if data.State == 0 {
		downTime = utils.IntToStr(int(data.CreateAt.Unix() + 15*60 - now))
		if now > data.CreateAt.Unix()+15*60 {
			data.State = 3
		}
		if utils.StrToInt(downTime) < 0 {
			downTime = "0"
		}
	}
	confirmAt := ""
	if data.ConfirmAt.IsZero() == false {
		confirmAt = data.ConfirmAt.Format("2006-01-02 15:04:05")
	}
	payAt := ""
	if data.PayAt.IsZero() == false {
		payAt = data.PayAt.Format("2006-01-02 15:04:05")
	}
	timer := ""
	if data.IsNow == 1 {
		timer = "立即提货"
	} else if data.Timer != "" {
		timer = data.Timer
	}
	orderInfo := []map[string]string{
		{"title": "订单编号", "content": utils.Int64ToStr(data.Oid)},
		{"title": "提货码", "content": data.Code},
		{"title": "下单时间", "content": data.CreateAt.Format("2006-01-02 15:04:05")},
		{"title": "付款时间", "content": payAt},
		{"title": "预计提货时间", "content": timer},
		{"title": "提货时间", "content": confirmAt},
		{"title": "预留电话", "content": data.Phone},
		{"title": "备注信息", "content": data.Memo},
	}
	goodsInfo := make([]map[string]string, 0)
	info := db.GetOrderInfoAllEg(MasterDb(c), utils.Int64ToStr(data.Oid))
	if info != nil {
		scheme, host := ImageBucket(c)

		for _, v := range *info {
			tmp := map[string]string{
				"img":     ImageFormatWithBucket(scheme, host, v.Img),
				"title":   v.Title,
				"price":   v.Price,
				"num":     utils.IntToStr(v.Num),
				"sku_str": "",
			}
			skuData := make([]md.Sku, 0)
			json.Unmarshal([]byte(v.SkuInfo), &skuData)
			skuStr := ""
			for _, v1 := range skuData {
				if skuStr != "" {
					skuStr += ";"
				}
				skuStr += v1.Value
			}
			tmp["sku_str"] = skuStr
			goodsInfo = append(goodsInfo, tmp)
		}
	}
	user1, _ := db.UserFindByID(MasterDb(c), data.Uid)
	userProfile, _ := db.UserProfileFindByID(MasterDb(c), data.Uid)
	nickname := ""
	headImg := ""
	if userProfile != nil {
		headImg = userProfile.AvatarUrl
	}
	if user1 != nil {
		if user1.Nickname != user1.Phone {
			user1.Nickname += " " + user1.Phone
		}
		nickname = user1.Nickname
	}
	tmp := map[string]interface{}{
		"oid":         utils.Int64ToStr(data.Oid),
		"label":       "自提",
		"username":    nickname,
		"head_img":    headImg,
		"commission":  data.Commission,
		"state":       utils.IntToStr(data.State),
		"state_str":   state[data.State],
		"amount":      data.Amount,
		"all_amount":  utils.Float64ToStr(utils.StrToFloat64(data.Amount) + utils.StrToFloat64(data.Coupon)),
		"coupon":      data.Coupon,
		"num":         utils.IntToStr(data.Num),
		"code":        data.Code,
		"down_time":   downTime,
		"order_info":  orderInfo,
		"goods_info":  goodsInfo,
		"goods_count": utils.IntToStr(len(goodsInfo)),
	}
	if data.Type == 1 {
		tmp["label"] = "外卖"
	}
	e.OutSuc(c, tmp, nil)
	return
}
func StoreOrderConfirm(c *gin.Context) {
	var arg map[string]string
	if err := c.ShouldBindJSON(&arg); err != nil {
		e.OutErr(c, e.ERR_INVALID_ARGS, err)
		return
	}
	// 加锁 防止并发提取
	mutexKey := fmt.Sprintf("%s:team.StoreOrderConfirm:%s", c.GetString("mid"), arg["oid"])
	withdrawAvailable, err := cache.Do("SET", mutexKey, 1, "EX", 5, "NX")
	if err != nil {
		e.OutErr(c, e.ERR, err)
		return
	}
	if withdrawAvailable != "OK" {
		e.OutErr(c, e.ERR, e.NewErr(400000, "请求过于频繁，请稍后再试"))
		return
	}
	sess := MasterDb(c).NewSession()
	defer sess.Close()
	sess.Begin()
	order := db.GetOrder(sess, arg["oid"])
	if order == nil {
		sess.Rollback()
		e.OutErr(c, 400, e.NewErr(400, "订单不存在"))
		return
	}
	if order.State != 1 {
		sess.Rollback()
		e.OutErr(c, 400, e.NewErr(400, "订单不能确认"))
		return
	}
	order.State = 2
	order.UpdateAt = time.Now()
	order.ConfirmAt = time.Now()
	update, err := sess.Where("id=?", order.Id).Cols("state,confirm_at,update_at").Update(order)
	if update == 0 || err != nil {
		sess.Rollback()
		e.OutErr(c, 400, e.NewErr(400, "订单确认失败"))
		return
	}
	money := utils.StrToFloat64(order.Commission)
	if order.ParentUid > 0 {
		money = utils.StrToFloat64(order.Amount) - utils.StrToFloat64(order.AgentCommission)
	}
	if order.StoreType == 1 {
		money = utils.StrToFloat64(order.Amount) - utils.StrToFloat64(order.PlatformCommission)
	}
	bools := MoneyCheck(c, sess, order.StoreUid, order.ParentUid, order.StoreType, 0, 1, money, "订单核销", order.Oid)
	if bools == false {
		sess.Rollback()
		e.OutErr(c, 400, e.NewErr(400, "订单确认失败"))
		return
	}
	sess.Commit()
	e.OutSuc(c, "success", nil)
	return
}
func MoneyCheck(c *gin.Context, sess *xorm.Session, storeId, ParentUid, StoreType, types, ordType int, money float64, title string, oid int64) bool {
	amountData := db.GetStoreAmount(sess, storeId, ParentUid, StoreType)
	if amountData == nil {
		amountData = &model.CommunityTeamStoreAmount{
			Uid:       storeId,
			ParentUid: ParentUid,
			StoreType: StoreType,
		}
		insert, err := sess.Insert(amountData)
		if insert == 0 || err != nil {
			return false
		}
	}
	before := amountData.Amount
	if types == 1 {
		amountData.Amount = utils.Float64ToStr(utils.StrToFloat64(amountData.Amount) - money)
		if utils.StrToFloat64(amountData.Amount) < 0 {
			return false
		}
	} else {
		amountData.Amount = utils.Float64ToStr(utils.StrToFloat64(amountData.Amount) + money)
	}
	update, err := sess.Where("id=?", amountData.Id).Cols("amount").Update(amountData)
	if update == 0 || err != nil {
		return false
	}
	var flow = &model.CommunityTeamStoreAmountFlow{
		Uid:          storeId,
		StoreType:    StoreType,
		ParentUid:    ParentUid,
		Amount:       utils.Float64ToStr(money),
		BeforeAmount: before,
		AfterAmount:  amountData.Amount,
		Oid:          oid,
		Type:         types,
		Title:        title,
		OrdType:      ordType,
		CreateAt:     time.Now(),
	}
	insert, err := sess.Insert(flow)
	if insert == 0 || err != nil {
		return false
	}
	return true
}
