package controllers

import (
	"log"
	"net/http"
	"time"

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

	"git.rosy.net.cn/jx-callback/globals"

	"git.rosy.net.cn/jx-callback/business/model/dao"

	"git.rosy.net.cn/jx-callback/business/model"

	"github.com/gorilla/websocket"

	"git.rosy.net.cn/baseapi/utils"

	"git.rosy.net.cn/jx-callback/business/jxstore/event"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	push "git.rosy.net.cn/jx-callback/business/jxutils/unipush"
	"git.rosy.net.cn/jx-callback/globals/api"
	"github.com/astaxie/beego/server/web"
)

// 操作事件明细相关API
type EventController struct {
	web.Controller
}

//连接的客户端,吧每个客户端都放进来
var clients = make(map[string][]*websocket.Conn)

//广播频道(通道)
var broadcast = make(chan map[string]*model.ImMessageRecord)

// 配置升级程序(升级为websocket)
var upgrader = websocket.Upgrader{}

// 定义我们的消息对象
type Message struct {
	Data interface{} `json:"data"`
}

// @Title 查询操作日志事件明细
// @Description 查询操作日志事件明细
// @Param	token			header		string	true	"认证token"
// @Param	apiFunctions	query		string	false	"功能名列表"
// @Param	name			query		string	false	"操作人姓名，支持模糊查询"
// @Param	operateTypes	query		string	false	"操作类型列表，1为修改，2为新增，4为删除"
// @Param	skuIDs			query		string	false	"商品ID列表"
// @Param	storeIDs		query		string	false	"门店ID列表"
// @Param	fromTime		query		string	false	"开始日期（包含），格式（2006-01-02 00:00:00)"
// @Param	toTime			query		string	false	"结束日期（包含），格式（2006-01-02 00:00:00)"
// @Param	keyword			query		string	false	"关键字"
// @Param	errType			query		int		false	"查询错误日志，默认0都查，1不查错误日志，-1只查错误日志"
// @Param	offset			query		int		false	"门店列表起始序号（以0开始，缺省为0）"
// @Param	pageSize		query		int		false	"门店列表页大小（缺省为30)"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /GetOperateEvents [get]
func (c *EventController) GetOperateEvents() {
	var storeIDList, skuIDList, operateTypeList []int
	var apiFunctionList []string
	c.callGetOperateEvents(func(params *tEventGetOperateEventsParams) (retVal interface{}, errCode string, err error) {
		if jxutils.Strings2Objs(params.StoreIDs, &storeIDList, params.SkuIDs, &skuIDList, params.ApiFunctions, &apiFunctionList, params.OperateTypes, &operateTypeList); err == nil {
			retVal, err = event.GetOperateEvents(params.Ctx, params.Name, apiFunctionList, operateTypeList, skuIDList, storeIDList, params.FromTime, params.ToTime, params.Keyword, params.ErrType, params.Offset, params.PageSize)
		}
		return retVal, "", err
	})
}

// @Title 各平台Cookie检查
// @Description 各平台Cookie检查
// @Param	token			header		string	true	"认证token"
// @Param	vendorIDs		query		string	false	"平台ID列表"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /GetCheckVendorCookie [get]
func (c *EventController) GetCheckVendorCookie() {
	var vendorIDList []int
	c.callGetCheckVendorCookie(func(params *tEventGetCheckVendorCookieParams) (retVal interface{}, errCode string, err error) {
		if jxutils.Strings2Objs(params.VendorIDs, &vendorIDList); err == nil {
			retVal, err = event.GetCheckVendorCookie(params.Ctx, vendorIDList, false)
		}
		return retVal, "", err
	})
}

// @Title 得到微信小程序码
// @Description 得到微信小程序码
// @Param	token		header		string	true	"认证token"
// @Param	scene		formData	string	true	"最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~，其它字符请自行编码为合法字符（因不支持%，中文无法使用 urlencode 处理，请使用其他编码方式）"
// @Param	page		formData	string	false	"必须是已经发布的小程序存在的页面（否则报错），例如 pages/index/index, 根路径前不要填加 /,不能携带参数（参数请放在scene字段里），如果不填写这个字段，默认跳主页面"
// @Param	minType		formData	string	false	"weChat或者tiktok"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /GetWeixinUnlimited [post]
func (c *EventController) GetWeixinUnlimited() {
	c.callGetWeixinUnlimited(func(params *tEventGetWeixinUnlimitedParams) (retVal interface{}, errCode string, err error) {
		result := make(map[string]interface{}, 2)
		//var wxApi *weixinapi.API
		//if web.BConfig.RunMode == "jxgy" {
		//	wxApi = api.WeixinMiniAPI
		//} else {
		//	wxApi = api.WeixinMiniAPI2
		//}
		// 微信小程序二维码
		weChatQr, err := api.WeixinMiniAPI2.GetUnlimited(params.Scene, params.Page)
		if err != nil || result == nil {
			return retVal, "", err
		}
		fileName := "wxcode" + utils.Int64ToStr(time.Now().Unix()) + ".jpg"
		weChatQrCode, err := jxutils.UploadExportContent([]byte(weChatQr["fakeData"].(string)), fileName)
		if err != nil || result == nil {
			return retVal, "", err
		}
		result["wxcode"] = weChatQrCode
		// 抖音小程序二维码
		tiktok, err := api.TiktokApi.GetTiktokQrCode(params.Scene)
		if err != nil || result == nil {
			return result, "", err
		}
		tiktokName := "tiktok" + utils.Int64ToStr(time.Now().Unix()) + ".jpg"
		tiktokQrCode, err := jxutils.UploadExportContent([]byte(tiktok["fakeData"].(string)), tiktokName)
		if err != nil || result == nil {
			return result, "", err
		}
		result["tiktok"] = tiktokQrCode

		return result, "", err
	})
}

// @Title 测试websocket
// @Description 测试websocket
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /TestWebsocket [get]
func (c *EventController) TestWebsocket() {
	// 解决跨域问题(微信小程序)
	upgrader.CheckOrigin = func(r *http.Request) bool {
		return true
	}
	//升级将HTTP服务器连接升级到WebSocket协议。
	//responseHeader包含在对客户端升级的响应中
	//请求。使用responseHeader指定Cookie（设置Cookie）和
	//应用程序协商的子目录（Sec WebSocket协议）。
	//如果升级失败，则升级将向客户端答复一个HTTP错误
	ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer ws.Close()

	//var clientID = c.GetString("clientID")
	//fmt.Printf("clientID=%s", clientID)
	var (
		vendorOrderID = c.GetString("vendorOrderID")
		msgMap        = make(map[string]*model.ImMessageRecord)
	)
	//将当前客户端放入map中
	clients[vendorOrderID] = append(clients[vendorOrderID], ws)

	db := dao.GetDB()
	if globals.IsProductEnv() {
		_, _, err = jxcontext.New(nil, c.GetString("token"), c.Ctx.ResponseWriter, c.Ctx.Request)
		if err != nil {
			msg := &CallResult{
				Code: model.ErrCodeGeneralFailed,
				Desc: err.Error(),
			}
			ws.WriteJSON(&msg)
		}
	}

	c.EnableRender = false //Beego不启用渲染

	var s *model.ImMessageRecord
	for {
		//接收客户端的消息
		err := ws.ReadJSON(&s)
		if err != nil {
			index := 0
			for k, v := range clients[vendorOrderID] {
				if v == ws {
					index = k
				}
			}
			wsList := clients[vendorOrderID]
			clients[vendorOrderID] = clients[vendorOrderID][0:0]
			clients[vendorOrderID] = append(clients[vendorOrderID], wsList[0:index]...)
			clients[vendorOrderID] = append(clients[vendorOrderID], wsList[index+1:len(wsList)]...)
			// delete(clients, ws) //删除map中的客户端
			break //结束循环
		} else {
			//接受消息 业务逻辑
			msgMap[vendorOrderID] = s
			broadcast <- msgMap
			dao.WrapAddIDCULDEntity(s, "")
			dao.CreateEntity(db, s)
			// fmt.Println("接受到从页面上反馈回来的信息 ", utils.Format4Output(s, false))
		}
	}
}

func init() {
	go handleMessages()
}

//广播推送消息
func handleMessages() {
	for {
		//读取通道中的消息
		msg := <-broadcast
		//循环map客户端
		for vendorOrderID, mmsg := range msg {
			for _, client := range clients[vendorOrderID] {
				//把通道中的消息发送给客户端
				err := client.WriteJSON(mmsg)
				if err != nil {
					client.Close() //关闭
					index := 0
					for k, v := range clients[vendorOrderID] {
						if v == client {
							index = k
						}
					}
					wsList := clients[vendorOrderID]
					clients[vendorOrderID] = clients[vendorOrderID][0:0]
					clients[vendorOrderID] = append(clients[vendorOrderID], wsList[0:index]...)
					clients[vendorOrderID] = append(clients[vendorOrderID], wsList[index+1:len(wsList)]...)
					// delete(clients, client) //删除map中的客户端
				}
			}
		}
	}
}

// @Title 查询聊天记录
// @Description 查询聊天记录
// @Param	token			header		string	true	"认证token"
// @Param	vendorOrderID	query		string	true	"订单号"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /GetImMessageRecord [get]
func (c *EventController) GetImMessageRecord() {
	c.callGetImMessageRecord(func(params *tEventGetImMessageRecordParams) (retVal interface{}, errCode string, err error) {
		retVal, err = dao.GetImMessageRecord(dao.GetDB(), params.VendorOrderID, "", 0, -1)
		return retVal, "", err
	})
}

// @Title 测试uniApp推送
// @Description 测试uniApp推送
// @Param	token			header		string	true	"认证token"
// @Param	vendorOrderID	query		string	true	"订单号"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /TestUniAppPush [get]
func (c *EventController) TestUniAppPush() {
	c.callTestUniAppPush(func(params *tEventTestUniAppPushParams) (retVal interface{}, errCode string, err error) {
		order, err := dao.GetSimpleOrder(dao.GetDB(), params.VendorOrderID)
		push.NotifyNewOrder(order)

		return retVal, errCode, err
	})
}
