package netprinter

import (
	"fmt"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	"strings"
	"time"

	"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"

	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/jx-callback/business/partner"

	"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
	"git.rosy.net.cn/jx-callback/business/model"
	"git.rosy.net.cn/jx-callback/business/model/dao"
	"git.rosy.net.cn/jx-callback/globals"
)

const (
	testVendorOrderID     = "test"
	realTestVendorOrderID = "901234567890123"
	realTestOrderVendorID = model.VendorIDJD
)

const (
	PrinterNotifyUserApplyCancel = 1
	PrinterNotifyNewAfsOrder     = 2
)

func PrintOrder(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (printResult *partner.PrinterStatus, err error) {
	storeID := vendorID
	if vendorOrderID == testVendorOrderID {
		vendorOrderID = realTestVendorOrderID
		vendorID = realTestOrderVendorID
	}
	order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
	if err == nil {
		if vendorOrderID == realTestVendorOrderID {
			order.StoreID = storeID
			order.JxStoreID = storeID
		}
		order.Status = model.OrderStatusNew
		printResult, err = PrintOrderByOrder(ctx, order, "order", nil)
	}
	return printResult, err
}

func PrintOrderByOrder(ctx *jxcontext.Context, order *model.GoodsOrder, printType string, afs *model.AfsOrder) (printResult *partner.PrinterStatus, err error) {
	printResult, err = PrintOrderByOrder4Store(ctx, order, jxutils.GetSaleStoreIDFromOrder(order), printType, afs)
	return printResult, err
}

func getStore4Print(db *dao.DaoDB, storeID int) (store *model.Store, err error) {
	for i := 0; i < 3; i++ {
		store2 := &model.Store{}
		store2.ID = storeID
		if err = dao.GetEntity(db, store2); err == nil {
			store = store2
			if store.LinkStoreID != 0 {
				storeID = store.LinkStoreID
			} else {
				break
			}
		} else {
			break
		}
	}
	if store != nil {
		err = nil
	}
	return store, err
}

// PrintOrderByOrder4Store 打印订单信息
func PrintOrderByOrder4Store(ctx *jxcontext.Context, order *model.GoodsOrder, storeID int, printType string, afs *model.AfsOrder) (printResult *partner.PrinterStatus, err error) {
	db := dao.GetDB()
	store, err := getStore4Print(db, storeID)
	if err == nil {
		handler, err := GetHandlerFromStore(store)
		if err != nil {
			return &partner.PrinterStatus{
				PrintResult: partner.PrintResultNoPrinter,
			}, nil
		}

		storeDetail, _ := dao.GetStoreDetail(db, storeID, order.VendorID, order.VendorOrgCode)
		if storeDetail == nil && order.VendorOrderID == testVendorOrderID {
			storeDetail = &dao.StoreDetail{
				BrandName:    testVendorOrderID,
				BrandIsPrint: model.NO,
			}
		}

		printResult, err = handler.PrintOrder(ctx, store, storeDetail, order, printType, afs)
		if err == nil {
			dao.SetOrderPrintFlag(db, ctx.GetUserName(), order.VendorOrderID, order.VendorID, true)
		}
	}
	if err != nil {
		globals.SugarLogger.Infof("PrintOrderByOrder4Store orderID:%s failed with error:%v", order.VendorOrderID, err)
	}
	return printResult, err
}

// PrintStoreStatus 打印门店信息
func PrintStoreStatus(ctx *jxcontext.Context, storeDetail *dao.StoreDetail, vendorId, storeStatus int) (printResult *partner.PrinterStatus, err error) {
	db := dao.GetDB()
	store, err := getStore4Print(db, storeDetail.ID)
	if err != nil {
		return &partner.PrinterStatus{
			PrintResult: partner.PrintResultNoPrinter,
		}, nil
	}

	handler, err := GetHandlerFromStore(store)
	if err != nil {
		return &partner.PrinterStatus{
			PrintResult: partner.PrintResultNoPrinter,
		}, nil
	}
	if storeStatus != 0 { // 失去授权
		store.Status = -9
	}
	printResult, err = handler.PrintStore(ctx, store, storeDetail, vendorId)
	if err == nil {
		dao.SetOrderPrintFlag(db, ctx.GetUserName(), "store print", vendorId, true)
	}
	return printResult, err
}

// PrintRefundOrCancelOrder 打印退单或取消订单信息
func PrintRefundOrCancelOrder(ctx *jxcontext.Context, printType int, order *model.GoodsOrder, storeID int) (printResult *partner.PrinterStatus, err error) {
	db := dao.GetDB()
	list, _ := dao.GetOrderStatusList(order.VendorOrderID, model.OrderTypePrintAfsOrder, order.VendorID)
	if list != nil && list[0].VendorOrderID != "" {
		return nil, err
	}
	store, err := getStore4Print(db, storeID)
	if err == nil {
		handler, err := GetHandlerFromStore(store)
		if err != nil {
			return &partner.PrinterStatus{
				PrintResult: partner.PrintResultNoPrinter,
			}, nil
		}
		storeDetail, _ := dao.GetStoreDetail(db, storeID, order.VendorID, order.VendorOrgCode)

		printResult, err = handler.PrintCancelOrRefundOrder(ctx, printType, store, storeDetail, order)
		if err == nil {
			dao.SetOrderPrintFlag(db, ctx.GetUserName(), order.VendorOrderID, order.VendorID, true)
			orderStatus := model.Order2Status(order)
			orderStatus.OrderType = model.OrderTypePrintAfsOrder
			orderStatus.StatusTime = time.Now()
			orderStatus.Status = model.AfsOrderStatusFinished
			orderStatus.VendorStatus = "success"
			orderStatus.Remark = fmt.Sprintf("%d[1取消/0售后],打印推送完成", printType)
			dao.CreateEntity(dao.GetDB(), orderStatus)
		}
	}
	if err != nil {
		globals.SugarLogger.Infof("PrintRefundOrCancelOrder orderID:%s failed with error:%v", order.VendorOrderID, err)
	}
	return printResult, err
}

func GetNetPrinterStatus(ctx *jxcontext.Context, storeID int) (printResult *partner.PrinterStatus, err error) {
	store := &model.Store{}
	store.ID = storeID
	db := dao.GetDB()
	if err = dao.GetEntity(db, store); err == nil {
		return getNetPrinterStatus(ctx, store)
	}
	return nil, err
}

func getNetPrinterStatus(ctx *jxcontext.Context, store *model.Store) (printResult *partner.PrinterStatus, err error) {
	handler, err := GetHandlerFromStore(store)
	if err != nil {
		return &partner.PrinterStatus{
			PrintResult: partner.PrintResultNoPrinter,
		}, err
	}
	return handler.GetPrinterStatus(ctx, store.PrinterSN, store.PrinterKey)
}

func GetHandlerFromStore(store *model.Store) (printerHandler partner.IPrinterHandler, err error) {
	if store.IsPrinterDisabled() {
		return nil, fmt.Errorf("门店%s没有启用网络打印机", store.Name)
	}
	if printerHandler = partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID); printerHandler == nil {
		return nil, fmt.Errorf("门店%s没有配置网络打印机", store.Name)
	}
	return printerHandler, nil
}

func BindPrinter(ctx *jxcontext.Context, storeID int, data string) (printResult *partner.PrinterStatus, err error) {
	store := &model.Store{}
	store.ID = storeID
	db := dao.GetDB()
	if err = dao.GetEntity(db, store); err == nil {
		var mapData map[string]interface{}
		if err = utils.UnmarshalUseNumber([]byte(data), &mapData); err == nil {
			printerVendorID := model.VendorIDUnknown
			if mapData["machineCode"] != nil {
				printerVendorID = model.VendorIDYiLianYun
			}
			if handler := partner.GetPrinterPlatformFromVendorID(printerVendorID); handler != nil {
				if store.PrinterVendorID > 0 && store.PrinterVendorID != printerVendorID {
					err = fmt.Errorf("门店:%d已经绑定了%s打印机，如果需要重新绑定，请联系运营先解绑", storeID, model.VendorChineseNames[store.PrinterVendorID])
				} else {
					bindResult, err2 := handler.BindPrinter(ctx, mapData)
					if err = err2; err == nil {
						store.PrinterVendorID = printerVendorID
						store.PrinterSN = bindResult.PrinterSN
						store.PrinterKey = bindResult.PrinterKey
						store.PrinterBindInfo = string(utils.MustMarshal(bindResult))
						if _, err = dao.UpdateEntity(db, store); err == nil {
							err = handler.EmptyPrintList(ctx, bindResult.PrinterSN, bindResult.PrinterKey)
							printResult, err = handler.GetPrinterStatus(ctx, bindResult.PrinterSN, bindResult.PrinterKey)
						}
					}
				}
			} else {
				err = fmt.Errorf("打印机类型:%d当前不支持", printerVendorID)
			}
		} else {
			err = fmt.Errorf("请扫描正确的二维码，如需要帮助，请联系运营！")
		}
	}
	return printResult, err
}

func RebindAllPrinters(ctx *jxcontext.Context, isForce, isAsync bool) (hint string, err error) {
	storeList, err := dao.GetRebindPrinterStoreList(dao.GetDB())
	if err == nil {
		var needRebindList []*model.Store
		bindResultMap := make(map[int]*partner.BindPrinterResult)
		now := time.Now()
		for _, v := range storeList {
			var bindResult partner.BindPrinterResult
			if err = utils.UnmarshalUseNumber([]byte(v.PrinterBindInfo), &bindResult); err == nil {
				if isForce || now.Sub(utils.Timestamp2Time(bindResult.ExpiresAt)) > -3*24*time.Hour {
					needRebindList = append(needRebindList, v)
					bindResultMap[v.ID] = &bindResult
				}
			}
		}

		if len(needRebindList) > 0 {
			db := dao.GetDB()
			task := tasksch.NewParallelTask("RebindAllPrinters", tasksch.NewParallelConfig().SetIsContinueWhenError(true).SetParallelCount(4), ctx,
				func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
					store := batchItemList[0].(*model.Store)
					if handler := partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID); handler != nil {
						bindResult, err2 := handler.RebindPrinter(ctx, bindResultMap[store.ID])
						if err = err2; err == nil {
							store.PrinterSN = bindResult.PrinterSN
							store.PrinterKey = bindResult.PrinterKey
							store.PrinterBindInfo = string(utils.MustMarshal(bindResult))
							if _, err = dao.UpdateEntity(db, store); err == nil {
								retVal = []int{1}
							}
						}
					} else {
						globals.SugarLogger.Warnf("RebindAllPrinters strange PrinterVendorID:%d", store.PrinterVendorID)
					}
					return retVal, err
				}, needRebindList)

			tasksch.ManageTask(task).Run()
			if !isAsync {
				hint = task.GetID()
			} else {
				result, err2 := task.GetResult(0)
				if err = err2; err == nil {
					hint = utils.Int2Str(len(result))
				}
			}
		}
	}
	return hint, err
}

func NofityOrderMsg(ctx *jxcontext.Context, storeID int, orderID, notifyMsg string) (err error) {
	if notifyMsg != "" {
		notifyMsg = strings.ReplaceAll(notifyMsg, ",", "")
		db := dao.GetDB()
		store := &model.Store{}
		store.ID = storeID
		if err = dao.GetEntity(db, store); err == nil {
			handler, err := GetHandlerFromStore(store)
			if err == nil {
				if globals.EnableStoreWrite {
					_, err = handler.PlayText(ctx, store.PrinterSN, store.PrinterKey, orderID, notifyMsg)
				}
			}
		}
	}
	return err
}
