package aaaa

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

	"github.com/go-resty/resty/v2"

	"nms_nbi/lib/dborm"
	"nms_nbi/lib/log"
	"nms_nbi/lib/oauth"
	"nms_nbi/lib/services"
	"nms_nbi/restagent/config"
)

var (
	UriAAAASSO = config.DefaultUriPrefix + "/aaaa/{apiVersion}/security/sso" // for 4A external

	CustomUriAAAASSO = config.UriPrefix + "/aaaa/{apiVersion}/security/sso" // for 4A external
)

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)
}

type AAAATicket struct {
	Ticket string `json:"ticket"`
}

type SSOResult struct {
	SSO struct {
		Result        string `json:"result"`
		ResultMsg     string `json:"result_msg"`
		Ticket        string `json:"ticket"`
		ResultMsgcode string `json:"result_msgcode"`
		Account       []struct {
			Accid string `json:"accid"`
		} `json:"account"`
	} `json:"sso"`
}

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

	vars := r.URL.Query()
	ticket := vars["ticket"]
	if len(ticket) == 0 {
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	log.Debug("ticket:", ticket)

	log.Debugf("r.RemoteAddr:%s r.Host: %s", r.RemoteAddr, r.Host)

	aaaaIp := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
	omcIp := r.Host[:strings.Index(r.Host, ":")]

	log.Debugf("aaaaIp=%s omcIp=%s", aaaaIp, omcIp)
	requestURI2NF := fmt.Sprintf("http://%s:8080/qryUserByTicket", aaaaIp)

	log.Debug("requestURI2NF:", requestURI2NF)

	aaaaTicket := &AAAATicket{
		Ticket: ticket[0],
	}

	body, err := json.Marshal(aaaaTicket)
	if err != nil {
		log.Error("Failed to json.Marshal:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	response, err := client.R().
		EnableTrace().
		SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
		SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
		SetBody(body).
		Post(requestURI2NF)
	if err != nil {
		log.Error("Failed to Post:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Debug("response:", response)

	switch response.StatusCode() {
	case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
		ssoResult := new(SSOResult)
		json.Unmarshal(response.Body(), ssoResult)
		var accid string
		if len(ssoResult.SSO.Account) != 0 {
			accid = ssoResult.SSO.Account[0].Accid
		}

		log.Debug("accid:", accid)
		exist, err := dborm.XormIsExistUser(accid)
		if err != nil {
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		token := oauth.GenRandToken("aaaa") // Generate new token to session ID
		affected, err := dborm.XormInsertSession(accid, r.RemoteAddr, token,
			config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session)
		if err != nil {
			log.Error("Failed to XormInsertSession:", err)
			if affected == -1 {
				services.ResponseForbidden403MultiLoginNotAllowed(w)
			} else {
				services.ResponseBadRequest400IncorrectLogin(w)
			}
			return
		}
		if exist == true {
			redirectUrl := fmt.Sprintf("http://%s:8888/home.html?user=%s&token=%s", omcIp, accid, token)
			services.ResponseRedirect(w, redirectUrl, accid, token)
			return
		} else {
			services.ResponseBadRequest400IncorrectLogin(w)
			return
		}
	default:
		services.ResponseForbidden403NotPermission(w)
		return
	}
}
