package manager

import (
	adminCharts "Wine-Server/handlers/manager/admin/charts"
	adminDashboard "Wine-Server/handlers/manager/admin/dashboard"
	adminTrade "Wine-Server/handlers/manager/admin/trade"
	adminWine "Wine-Server/handlers/manager/admin/wine"
	adminWorker "Wine-Server/handlers/manager/admin/worker"
	superCharts "Wine-Server/handlers/manager/super/charts"
	superConfig "Wine-Server/handlers/manager/super/config"
	superDashboard "Wine-Server/handlers/manager/super/dashboard"
	superOrder "Wine-Server/handlers/manager/super/order"
	superRecord "Wine-Server/handlers/manager/super/record"
	superRole "Wine-Server/handlers/manager/super/role"
	"Wine-Server/utils"
	"Wine-Server/utils/tables"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"strings"
)

func managerConnected(mid string, conn *websocket.Conn) *tables.ManagerTable {
	table := &tables.ManagerTable{Id: mid}
	err := table.Get()
	if err != nil {
		utils.Logger.Println("manager query failed:", err)
		_ = conn.WriteJSON(utils.WsError("manager query failed"))
		return nil
	}
	table.Last = utils.TimeNow()
	err = table.Update(utils.JsonType{"last": table.Last})
	if err != nil {
		utils.Logger.Println("update last active time failed:", err)
		_ = conn.WriteJSON(utils.WsError("Update last active time failed"))
		return nil
	}
	if _, exist := utils.ManagerWss[mid]; exist {
		_ = conn.WriteJSON(utils.WsEvent("onePageOnly", nil))
		return nil
	}
	utils.ManagerLock.Lock()
	utils.ManagerWss[mid] = conn
	utils.ManagerLock.Unlock()
	utils.Logger.Printf("manager[%s] connected\n", mid)
	return table
}

func managerDisconnect(mid string) {
	utils.ManagerLock.Lock()
	delete(utils.ManagerWss, mid)
	utils.ManagerLock.Unlock()
	utils.Logger.Printf("manager[%s] disconnected\n", mid)
}

func loginSocket(conn *websocket.Conn) (string, error) {
	var mid string
	for {
		var msg utils.WsMsg
		err := conn.ReadJSON(&msg)
		if err != nil {
			_ = conn.Close()
			return "", err
		}
		switch msg.Event {
		case "pin":
			keepAlive(conn)
			break
		case "getUserInfo": // in case: redis token expired
			break
		case "login":
			mid, err = userLogin(conn, msg.Data)
			if err == nil {
				return mid, nil
			}
			break
		default:
			utils.Logger.Println(msg.Event)
			_ = conn.WriteJSON(utils.WsError("loginSocket event only"))
			break
		}
	}
}

func SocketHandler(ctx *gin.Context) {
	conn, err := utils.UpgradeHttp2Ws.Upgrade(ctx.Writer, ctx.Request, nil)
	if err != nil {
		utils.Logger.Println("can't establish manager socket connect")
		ctx.JSON(utils.HttpError, utils.Fail("can't establish socket connect"))
		return
	}
	getSecrets(conn)
	var mid string
	token := ctx.Param("token")
	if token == "undefined" { // no token -> login
		mid, err = loginSocket(conn)
	} else {
		mid, err = utils.Redis.Get(utils.WxPayCli, token).Result()
		if err != nil { // expired -> login
			_ = conn.WriteJSON(utils.WsEvent("tokenExpired", nil))
			mid, err = loginSocket(conn)
		} else { // update expire time
			err = utils.Redis.Expire(utils.WxPayCli, token, utils.Duration(7*24*60*60)).Err()
			if err != nil {
				utils.Logger.Println(err)
			}
		}
	}

	if err != nil {
		return
	}
	manager := managerConnected(mid, conn)
	if manager == nil {
		return
	}
	defer managerDisconnect(mid)

	for {
		var msg utils.WsMsg
		err = conn.ReadJSON(&msg)
		if err != nil {
			return
		}
		if msg.Event == "pin" {
			keepAlive(conn)
		} else if msg.Event == "getUserInfo" {
			getUserInfo(conn, manager)
		} else if msg.Event == "logout" {
			userLogout(conn, msg.Data)
		} else if strings.HasPrefix(msg.Event, "superDashboard") { // super:
			superDashboard.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "superRole") {
			superRole.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "superOrder") {
			superOrder.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "superConfig") {
			superConfig.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "superRecord") {
			superRecord.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "superCharts") {
			superCharts.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "adminDashboard") { // admin:
			adminDashboard.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "adminWorker") {
			adminWorker.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "adminTrade") {
			adminTrade.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "adminWine") {
			adminWine.Handle(msg, conn, manager)
		} else if strings.HasPrefix(msg.Event, "adminCharts") {
			adminCharts.Handle(msg, conn, manager)
		} else {
			_ = conn.WriteJSON(utils.WsError("unrecognized event"))
		}
	}
}
