package ue

import (
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"ems.agt/lib/dborm"
	"ems.agt/lib/global"
	"ems.agt/lib/log"
	"ems.agt/lib/services"
	"ems.agt/restagent/config"
	tokenConst "ems.agt/src/framework/constants/token"
	"github.com/go-resty/resty/v2"
	"github.com/gorilla/mux"
)

// AmfNBInfo AMF的NodeB信息
type AmfNBInfo struct {
	ID      string `json:"id"`      //NodeB ID
	Name    string `json:"name"`    // NodeB name
	Address string `json:"address"` // 基站地址
	UENum   int    `jons:"ueNum"`   // UE数量
}

// SmfUENum SMF在线用户数
type SmfUENum struct {
	UENum int `json:"ueNum"` // 当前在线用户数
}

// SmfUEInfo SMF在线用户信息
type SmfUEInfo struct {
	IMSI           string `json:"imsi"`
	MSISDN         string `json:"msisdn"`
	RatType        string `json:"ratType"`
	PduSessionInfo []struct {
		PduSessionID int    `json:"pduSessionID"`
		IPv4         string `json:"ipv4"`
		IPv6         string `json:"ipv6"`
		Dnn          string `json:"dnn"`
		Tai          string `json:"tai"`
		SstSD        string `json:"sstSD"`
		UpfN3IP      string `json:"upfN3IP"`
		RanN3IP      string `json:"ranN3IP"`
		Activetime   string `json:"activeTime"`
	} `json:"pduSessionInfo"`
}

// ImsUEInfo IMS在线用户信息
type ImsUEInfo struct {
	IMSI       string `json:"imsi"`
	MSISDN     string `json:"msisdn"`
	IMPU       string `json:"impu"`
	Barring    int    `json:"barring"`
	RegState   int    `json:"regState"`
	Activetime string `json:"activeTime"`
}

var (
	UriNBInfo = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/nbInfo"
	UriUEInfo = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueInfo"
	UriUENum  = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueNum"

	CustomUriNBInfo = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/nbInfo"
	CustomUriUEInfo = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueInfo"
	CustomUriUENum  = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueNum"
)

var client = resty.New()

func init() {
	/*
		client.
			SetTimeout(10 * time.Second).
			SetRetryCount(1).
			SetRetryWaitTime(1 * time.Second).
			SetRetryMaxWaitTime(2 * time.Second).
			SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
				return 0, errors.New("quota exceeded")
			})
	*/
	client.SetTimeout(3 * time.Second)
}

// Get UEInfo from NF/NFs
func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) {
	log.Info("GetUEInfoFromNF processing... ")

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	//neTypeLower := strings.ToLower(neType)
	var neId string
	neIds := services.GetParamsArrByName("neId", r)
	if len(neIds) == 1 {
		neId = neIds[0]
	} else {
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	token, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}
	log.Debug("token:", token)

	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Error("Failed to XormGetNeInfo:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if neInfo == nil {
		err := global.ErrCMNotFoundTargetNE
		log.Error(global.ErrCMNotFoundTargetNE)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Trace("neInfo:", neInfo)

	hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
	requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI)

	log.Debug("requestURI2NF:", requestURI2NF)

	resp, err := client.R().
		EnableTrace().
		SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}).
		SetHeaders(map[string]string{"accessToken": token}).
		SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
		SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
		Get(requestURI2NF)
	if err != nil {
		log.Error("Get system state from NF is failed:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else {
		var response services.DataResponse
		_ = json.Unmarshal(resp.Body(), &response)
		services.ResponseWithJson(w, resp.StatusCode(), response)
		return
	}
}

// Get UEInfo from SMF
func GetUENumFromNF(w http.ResponseWriter, r *http.Request) {
	log.Info("GetUENumFromNF processing... ")

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	//neTypeLower := strings.ToLower(neType)
	var neId string
	neIds := services.GetParamsArrByName("neId", r)
	if len(neIds) == 1 {
		neId = neIds[0]
	} else {
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	token, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}
	log.Debug("token:", token)

	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Error("Failed to XormGetNeInfo:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if neInfo == nil {
		err := global.ErrCMNotFoundTargetNE
		log.Error(global.ErrCMNotFoundTargetNE)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Trace("neInfo:", neInfo)

	hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
	requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI)

	log.Debug("requestURI2NF:", requestURI2NF)

	resp, err := client.R().
		EnableTrace().
		SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}).
		SetHeaders(map[string]string{"accessToken": token}).
		SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
		SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
		Get(requestURI2NF)
	if err != nil {
		log.Error("Get system state from NF is failed:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else {
		var response services.DataResponse
		_ = json.Unmarshal(resp.Body(), &response)
		services.ResponseWithJson(w, resp.StatusCode(), response)
		return
	}
}

// Get UEInfo from NF/NFs
func GetNBInfoFromNF(w http.ResponseWriter, r *http.Request) {
	log.Info("GetNBInfoFromNF processing... ")

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	//neTypeLower := strings.ToLower(neType)
	var neId string
	neIds := services.GetParamsArrByName("neId", r)
	if len(neIds) == 1 {
		neId = neIds[0]
	} else {
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	token, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}
	log.Debug("token:", token)

	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Error("Failed to XormGetNeInfo:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if neInfo == nil {
		err := global.ErrCMNotFoundTargetNE
		log.Error(global.ErrCMNotFoundTargetNE)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Trace("neInfo:", neInfo)

	hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
	requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI)

	log.Debug("requestURI2NF:", requestURI2NF)

	resp, err := client.R().
		EnableTrace().
		SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}).
		SetHeaders(map[string]string{"accessToken": token}).
		SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
		SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
		Get(requestURI2NF)
	if err != nil {
		log.Error("Get system state from NF is failed:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else {
		var response services.DataResponse
		_ = json.Unmarshal(resp.Body(), &response)
		services.ResponseWithJson(w, resp.StatusCode(), response)
		return
	}
}
