package mml

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

	"ems.agt/lib/dborm"
	"ems.agt/lib/global"
	"ems.agt/lib/log"
	"ems.agt/lib/mmlp"
	"ems.agt/lib/services"
	"ems.agt/restagent/config"

	tokenConst "ems.agt/src/framework/constants/token"
	"github.com/gorilla/mux"
)

const (
	//经过测试，linux下，延时需要大于100ms
	TIME_DELAY_AFTER_WRITE = 200
)

type Response struct {
	Data []string `json:"data"`
}

type MMLRequest struct {
	MML []string `json:"mml"`
}

var (
	// MML interface
	UriMML        = config.DefaultUriPrefix + "/operationManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml"
	UriMMLDiscard = config.DefaultUriPrefix + "/opeartionManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml"
	UriNeOmMml    = config.DefaultUriPrefix + "/omManagement/{apiVersion}/mml/{netype}/{neid}"
	UriOmMmlExt   = config.DefaultUriPrefix + "/{managedType}/{apiVersion}/elementType/OMC/objectType/mml"
	UriOmMmlInt   = config.DefaultUriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}"

	CustomUriMML      = config.UriPrefix + "/operationManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml"
	CustomUriNeOmMml  = config.UriPrefix + "/omManagement/{apiVersion}/mml/{netype}/{neid}"
	CustomUriOmMmlExt = config.UriPrefix + "/opeartionManagement/{apiVersion}/elementType/OMC/objectType/mml"
	CustomUriOmMmlInt = config.UriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}"
)

func PostMMLToNF(w http.ResponseWriter, r *http.Request) {
	log.Debug("PostMMLToNF processing... ")

	token, err := services.CheckExtValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}
	pack := "mml"
	vars := mux.Vars(r)
	module := vars["managedType"]
	neType := vars["elementTypeValue"]
	params := r.URL.Query()
	neId := params["ne_id"]
	if len(neId) == 0 {
		log.Error("NOT FOUND ne_id")
		services.ResponseBadRequest400WrongParamValue(w)
		return
	}
	log.Debug("neType:", neType, "neId", neId)

	log.Debugf("token:%s, method:%s, managementType:%s dbname:%s, tbname:%s pack:%s",
		token, r.Method, module, neType, neId[0], pack)

	var buf [8192]byte
	var n int
	var mmlResult []string

	// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, neType, neId[0], pack)
	// if err != nil {
	// 	log.Error("Failed to get permission:", err)
	// 	errMsg := fmt.Sprintf("RetCode = -1 operation failed: do not have the operation permissions")
	// 	log.Error(errMsg)
	// 	mmlResult = append(mmlResult, errMsg)
	// 	response := Response{mmlResult}
	// 	services.ResponseWithJson(w, http.StatusOK, response)
	// 	//services.ResponseForbidden403NotPermission(w)
	// 	return
	// }
	// if !exist {
	// 	log.Error("Not permission!")
	// 	errMsg := fmt.Sprintf("RetCode = -1 operation failed: do not have the operation permissions")
	// 	log.Error(errMsg)
	// 	mmlResult = append(mmlResult, errMsg)
	// 	response := Response{mmlResult}
	// 	services.ResponseWithJson(w, http.StatusOK, response)
	// 	//services.ResponseForbidden403NotPermission(w)
	// 	return
	// }

	if strings.ToLower(neType) == "omc" {
		PostMMLToOMC(w, r)
		return
	}

	neInfo := new(dborm.NeInfo)
	neInfo, err = dborm.XormGetNeInfo(neType, neId[0])
	if err != nil {
		log.Error("dborm.XormGetNeInfo is failed:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}

	if neInfo != nil {
		hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port)
		conn, err := net.Dial("tcp", hostMML)
		if err != nil {
			errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err)
			log.Error(errMsg)
			mmlResult = append(mmlResult, errMsg)
			response := Response{mmlResult}
			services.ResponseWithJson(w, http.StatusOK, response)
			return
		}

		loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password)
		n, err = conn.Write([]byte(loginStr))
		if err != nil {
			log.Errorf("Error: %s", err.Error())
			return
		}

		time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)

		n, err = conn.Read(buf[0:])
		if err != nil {
			log.Errorf("Error: %s", err.Error())
			return
		}
		log.Debug(string(buf[0:n]))

		body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
		if err != nil {
			log.Error("io.ReadAll is failed:", err)
			services.ResponseNotFound404UriNotExist(w, r)
			return
		}
		log.Debug("Body:", string(body))

		mmlRequest := new(MMLRequest)
		_ = json.Unmarshal(body, mmlRequest)

		for _, mml := range mmlRequest.MML {
			mmlCommand := fmt.Sprintf("%s\n", mml)
			log.Debug("mml command:", mmlCommand)
			_, err = conn.Write([]byte(mmlCommand))
			if err != nil {
				log.Errorf("Error: %s", err.Error())
				return
			}
			time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)

			n, err = conn.Read(buf[0:])
			if err != nil {
				log.Errorf("Error: %s", err.Error())
				return
			}
			log.Debug(string(buf[0 : n-len(neType)-2]))
			mmlResult = append(mmlResult, string(buf[0:n-len(neType)-2]))
		}
	}

	response := Response{mmlResult}
	services.ResponseWithJson(w, http.StatusOK, response)
}

func PostMMLToOMC(w http.ResponseWriter, r *http.Request) {
	log.Debug("PostMMLToOMC processing... ")

	token, err := services.CheckExtValidRequest(w, r)
	if err != nil {
		log.Error("Failed to CheckMmlValidRequest:", err)
		return
	}

	params := r.URL.Query()
	neId := params["ne_id"]
	if len(neId) == 0 {
		log.Error("NOT FOUND ne_id ")
		services.ResponseBadRequest400WrongParamValue(w)
		return
	}

	neInfo := new(dborm.NeInfo)
	neInfo, err = dborm.XormGetNeInfo("OMC", neId[0])
	if err != nil {
		log.Error("dborm.XormGetNeInfo is failed:", err)
		services.ResponseInternalServerError500DatabaseOperationFailed(w)
		return
	}
	log.Trace("neInfo:", neInfo)

	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
	if err != nil {
		log.Error("io.ReadAll is failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	log.Debug("Body:", string(body))

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

	omcMmlVar := &mmlp.MmlVar{
		Version:       "16.1.1",
		Output:        mmlp.DefaultFormatType,
		MmlHome:       config.GetYamlConfig().MML.MmlHome,
		Limit:         50,
		User:          "",
		SessionToken:  token,                               // 旧token
		Authorization: r.Header.Get(tokenConst.HEADER_KEY), // 请求Token
		HttpUri:       hostUri,
		UserAgent:     config.GetDefaultUserAgent(),
	}
	mmlRequest := new(MMLRequest)
	_ = json.Unmarshal(body, mmlRequest)

	var mmlResult []string
	mmlLine := strings.Join(mmlRequest.MML, ";")

	var mmlCmds []mmlp.MmlCommand
	if err = mmlp.ParseMMLCommand(mmlLine, &mmlCmds); err != nil {
		response := fmt.Sprintf("parse command error: %v\n", err)
		mmlResult = append(mmlResult, response)
	}

	for _, mmlCmd := range mmlCmds {
		output, err := mmlp.TransMml2HttpReq(omcMmlVar, &mmlCmd)
		if err != nil {
			response := fmt.Sprintf("translate MML command error: %v]\n", err)
			mmlResult = append(mmlResult, response)
		}
		mmlResult = append(mmlResult, string(*output))
	}

	response := Response{mmlResult}
	services.ResponseWithJson(w, http.StatusOK, response)
}
