package controllers

import (
	"encoding/json"
	"fmt"
	"intent-system/pkg/config"
	"intent-system/pkg/dal/core"
	"intent-system/pkg/dal/ws"
	"intent-system/pkg/itypes"
	"intent-system/pkg/middleware"
	"intent-system/pkg/sessions"
	"net/http"

	"github.com/civet148/sqlca/v2"

	"github.com/civet148/log"
	"github.com/gin-gonic/gin"
)

type Controller struct {
	cfg            *config.Config
	BizCore        *core.BizCore
	CommonCore     *core.CommonCore
	PlatformCore   *core.PlatformCore
	CustomerCore   *core.CustomerCore
	DeployCore     *core.DeployCore
	GatewayCore    *core.GatewayCore
	SchedulerCore  *core.SchedulerCore
	DeployTaskCore *core.DeployTaskCore

	DeployProgressPool *ws.WebSocketPool //
}

func NewController(cfg *config.Config) *Controller {
	var err error
	var my, pg *sqlca.Engine
	my, err = sqlca.NewEngine(cfg.DSN)
	if err != nil {
		log.Panic("MySQL source [%s] connect error [%s]", cfg.DSN, err.Error())
		return nil
	}
	my.Debug(cfg.Debug)     //SQL调试日志
	my.SlowQuery(true, 800) //慢查询告警
	pg, err = sqlca.NewEngine(cfg.Postgresql)
	if err != nil {
		log.Panic(" Postgresql source [%s] connect error [%s]", cfg.Postgresql, err.Error())
		return nil
	}
	pg.Debug(cfg.Debug)     //SQL调试日志
	pg.SlowQuery(true, 800) //慢查询告警
	return &Controller{
		cfg:                cfg,
		BizCore:            core.NewBizCore(cfg, my),
		CommonCore:         core.NewCommonCore(cfg, my),
		PlatformCore:       core.NewPlatformCore(cfg, my),
		CustomerCore:       core.NewCustomerCore(cfg, my),
		DeployCore:         core.NewDeployCore(cfg, my),
		GatewayCore:        core.NewGatewayCore(cfg, my),
		SchedulerCore:      core.NewSchedulerCore(cfg, my, pg),
		DeployProgressPool: ws.NewWebSocketPool(),
	}
}

func (m *Controller) OK(c *gin.Context, data interface{}, count int, total int64) {
	var bc = itypes.BizOK
	if data == nil {
		data = struct{}{}
	}
	var r = &itypes.HttpResponse{
		Header: itypes.HttpHeader{
			Code:    bc.Code,
			Message: bc.Message,
			Count:   count,
			Total:   total,
		},
		Data: data,
	}
	c.JSON(http.StatusOK, r)
	c.Abort()
}

func (m *Controller) Error(c *gin.Context, bc itypes.BizCode) {
	var r = &itypes.HttpResponse{
		Header: itypes.HttpHeader{
			Code:    bc.Code,
			Message: bc.Message,
			Count:   0,
		},
		Data: struct{}{},
	}
	log.Errorf("[Controller] response error code [%d] message [%s]", bc.Code, bc.Message)
	c.JSON(http.StatusOK, r)
	c.Abort()
}

func (m *Controller) ErrorStatus(c *gin.Context, status int, message string) {
	log.Errorf("[Controller] http status code [%d] message [%s]", status, message)
	c.String(status, message)
	c.Abort()
}

func (m *Controller) RpcResult(c *gin.Context, data interface{}, err error, id interface{}) {
	var status = http.StatusOK
	var strResp string
	if err != nil {
		status = http.StatusInternalServerError
		data = &itypes.RpcResponse{
			Id:      id,
			JsonRpc: "2.0",
			Error: itypes.RpcError{
				Code:    itypes.CODE_INTERNAL_SERVER_ERROR,
				Message: err.Error(),
			},
			Result: nil,
		}
	}
	switch data.(type) {
	case string:
		strResp = data.(string)
	default:
		{
			b, _ := json.Marshal(data)
			strResp = string(b)
		}
	}

	c.String(status, strResp)
	c.Abort()
}

func (m *Controller) GetClientIP(c *gin.Context) (strIP string) {
	return c.ClientIP()
}
func (m *Controller) GetClientSystemOS(c *gin.Context) (strOS string) {
	userAgent := c.GetHeader("User-Agent")
	return userAgent
}

func (m *Controller) ContextFromAuthToken(c *gin.Context) (ctx *itypes.Context, ok bool) {
	var err error
	ctx = sessions.GetContext(c)
	if ctx == nil {
		err = log.Errorf("user session context is nil, token [%s]", middleware.GetAuthToken(c))
		m.Error(c, itypes.NewBizCode(itypes.CODE_UNAUTHORIZED, err.Error()))
		return
	}
	return ctx, true
}

func (m *Controller) ContextPlatformPrivilege(c *gin.Context, privileges ...string) (ctx *itypes.Context, ok bool) {
	var err error
	ctx = sessions.GetContext(c)
	if ctx == nil {
		err = log.Errorf("user session context is nil, token [%s]", middleware.GetAuthToken(c))
		m.Error(c, itypes.NewBizCode(itypes.CODE_UNAUTHORIZED, err.Error()))
		return
	}
	for _, auth := range privileges {
		if m.PlatformCore.CheckPrivilege(c, ctx, auth) {
			return ctx, true
		}
	}
	err = log.Errorf("user name [%s] id [%v] have no privilege %+v", ctx.UserName(), ctx.UserId(), privileges)
	m.Error(c, itypes.NewBizCode(itypes.CODE_ACCESS_DENY, err.Error()))
	return ctx, false
}

func (m *Controller) CheckPrivilege(c *gin.Context, ctx *itypes.Context, privileges ...string) (ok bool) {
	for _, auth := range privileges {
		if m.PlatformCore.CheckPrivilege(c, ctx, auth) {
			return true
		}
	}
	log.Warnf("operator name [%s] id [%v] have no privilege %+v", ctx.UserName(), ctx.UserId(), privileges)
	return false
}

func (m *Controller) bindJSON(c *gin.Context, req interface{}) (err error) {
	if err = c.ShouldBindJSON(req); err != nil {
		err = log.Errorf("invalid json or required fields, error [%s]", err)
		m.Error(c, itypes.NewBizCode(itypes.CODE_INVALID_JSON_OR_REQUIRED_PARAMS, err.Error()))
		c.Abort()
		return
	}

	body, _ := json.MarshalIndent(req, "", "\t")
	log.Debugf("request from [%s] body [%+v]", c.ClientIP(), string(body))
	return nil
}

func (m *Controller) isNilString(strIn string) bool {
	if strIn == "" {
		return true
	}
	return false
}

func (m *Controller) isZero(n interface{}) bool {
	strNumber := fmt.Sprintf("%v", n)
	if strNumber == "0" {
		return true
	}
	return false
}
