package fm

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"nms_nbi/lib/dborm"
	"nms_nbi/lib/log"
	"nms_nbi/restagent/config"

	"github.com/linxGnu/gosmpp"
	"github.com/linxGnu/gosmpp/data"
	"github.com/linxGnu/gosmpp/pdu"
)

func AlarmForwardBySMS(alarmData *Alarm) error {
	log.Info("AlarmForwardBySMS processing... ")

	SMSFforwardconfig := config.GetYamlConfig().Alarm.SMS
	// 阿里云短信API的请求地址
	apiURL := SMSFforwardconfig.ApiURL

	// 阿里云短信API的AccessKey ID和AccessKey Secret
	//accessKeyID := SMSFforwardconfig.AccessKeyID
	accessKeySecret := SMSFforwardconfig.AccessKeySecret

	toUsers, err := dborm.XormGetAlarmForward("SMS")
	if err != nil {
		log.Error("Failed to XormGetAlarmForward:", err)
		return err
	} else if toUsers == nil {
		err := errors.New("not found forward phone number")
		log.Error(err)
		return err
	}

	for _, toUser := range *toUsers {
		// 短信相关参数
		params := url.Values{}
		params.Set("PhoneNumbers", toUser)
		params.Set("SignName", SMSFforwardconfig.SignName)
		params.Set("TemplateCode", SMSFforwardconfig.TemplateCode)
		params.Set("TemplateParam", `{"message":"alarm"}`)

		// 构建请求URL
		reqURL := apiURL + "?Action=SendSms&" + params.Encode()

		// 创建HTTP请求
		req, err := http.NewRequest("GET", reqURL, nil)
		if err != nil {
			log.Error("Failed to create request:", err)
			return err
		}

		// 添加请求头部
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		req.Header.Set("Authorization", "APPCODE "+accessKeySecret)

		forwardLog := &dborm.AlarmForwardLog{
			NeType:     alarmData.NeType,
			NeID:       alarmData.NeId,
			AlarmID:    alarmData.AlarmId,
			AlarmTitle: alarmData.AlarmTitle,
			AlarmSeq:   alarmData.AlarmSeq,
			EventTime:  alarmData.EventTime,
			ToUser:     toUser,
		}
		// 发送请求
		client := &http.Client{}
		resp, err := client.Do(req)
		if err != nil {
			operResult := fmt.Sprintf("Failed to send request:%v", err)
			log.Error(operResult)
			forwardLog.OperResult = operResult
			affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
			if err != nil && affected <= 0 {
				log.Error("Failed to insert data:", err)
			}
			continue
		}
		defer resp.Body.Close()

		// 解析响应
		if resp.StatusCode == http.StatusOK {
			operResult := "SMS sent successfully!"
			log.Info(operResult)
			forwardLog.OperResult = operResult
			affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
			if err != nil && affected <= 0 {
				log.Error("Failed to insert data:", err)
				continue
			}
		} else {
			operResult := fmt.Sprintf("Failed to send SMS, StatusCode=%d", resp.StatusCode)
			log.Error(operResult)
			forwardLog.OperResult = operResult
			affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
			if err != nil && affected <= 0 {
				log.Error("Failed to insert data:", err)
				continue
			}
		}
	}
	return nil
}

func AlarmForwardBySMPP(alarmData *Alarm) error {
	log.Info("AlarmForwardBySMPP processing... ")

	auth := gosmpp.Auth{
		SMSC:       config.GetYamlConfig().Alarm.SMSC.Addr,
		SystemID:   config.GetYamlConfig().Alarm.SMSC.UserName,
		Password:   config.GetYamlConfig().Alarm.SMSC.Password,
		SystemType: "",
	}

	// conn, err := gosmpp.NonTLSDialer(auth.SMSC)
	// connection := gosmpp.NewConnection(conn)

	trans, err := gosmpp.NewSession(
		gosmpp.TXConnector(gosmpp.NonTLSDialer, auth),
		gosmpp.Settings{
			ReadTimeout: 2 * time.Second,

			OnPDU: func(p pdu.PDU, _ bool) {
				log.Debug("%+v", p)
			},

			OnSubmitError: func(_ pdu.PDU, err error) {
				log.Error(err)
			},

			OnRebindingError: func(err error) {
				log.Error(err)
			},

			OnClosed: func(state gosmpp.State) {
				log.Error(state)
			},
		}, -1)
	if err != nil {
		log.Error(err)
		return err
	}
	defer func() {
		_ = trans.Close()
	}()

	toUsers, err := dborm.XormGetAlarmForward("SMS")
	if err != nil {
		log.Error("Failed to XormGetAlarmForward:", err)
		return err
	} else if toUsers == nil {
		err := errors.New("not found forward phone number")
		log.Error(err)
		return err
	}
	// sending SMS(s)
	for _, toUser := range *toUsers {
		forwardLog := &dborm.AlarmForwardLog{
			NeType:     alarmData.NeType,
			NeID:       alarmData.NeId,
			AlarmID:    alarmData.AlarmId,
			AlarmTitle: alarmData.AlarmTitle,
			AlarmSeq:   alarmData.AlarmSeq,
			EventTime:  alarmData.EventTime,
			ToUser:     toUser,
		}
		message := alarmData.AlarmTitle + "from" + alarmData.NeType + alarmData.NeId + "at" + alarmData.EventTime
		if err = trans.Transceiver().Submit(newSubmitSM(toUser, message)); err != nil {
			operResult := fmt.Sprintf("Failed to submit short message:%v", err)
			log.Error(operResult)
			forwardLog.OperResult = operResult
		} else {
			operResult := "SMS sent successfully!"
			log.Trace(operResult)
			forwardLog.OperResult = operResult
		}

		affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
		if err != nil && affected <= 0 {
			log.Error("Failed to insert data:", err)
			continue
		}
	}
	return nil
}

func handlePDU() func(pdu.PDU) (pdu.PDU, bool) {
	return func(p pdu.PDU) (pdu.PDU, bool) {
		switch pd := p.(type) {
		case *pdu.Unbind:
			log.Trace("Unbind Received")
			return pd.GetResponse(), true

		case *pdu.UnbindResp:
			log.Trace("UnbindResp Received")

		case *pdu.SubmitSMResp:
			log.Trace("SubmitSMResp Received")

		case *pdu.GenericNack:
			log.Trace("GenericNack Received")

		case *pdu.EnquireLinkResp:
			fmt.Println("EnquireLinkResp Received")

		case *pdu.EnquireLink:
			log.Trace("EnquireLink Received")
			return pd.GetResponse(), false

		case *pdu.DataSM:
			log.Trace("DataSM receiver")
			return pd.GetResponse(), false

		case *pdu.DeliverSM:
			log.Trace("DeliverSM receiver")
			return pd.GetResponse(), false
		}
		return nil, false
	}
}

func newSubmitSM(phoneNumber string, message string) *pdu.SubmitSM {
	// build up submitSM
	srcAddr := pdu.NewAddress()
	srcAddr.SetTon(5)
	srcAddr.SetNpi(0)
	_ = srcAddr.SetAddress("alarm notification:")

	destAddr := pdu.NewAddress()
	destAddr.SetTon(1)
	destAddr.SetNpi(1)
	_ = destAddr.SetAddress(phoneNumber)

	submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
	submitSM.SourceAddr = srcAddr
	submitSM.DestAddr = destAddr
	_ = submitSM.Message.SetMessageWithEncoding(message, data.UCS2)
	submitSM.ProtocolID = 0
	submitSM.RegisteredDelivery = 1
	submitSM.ReplaceIfPresentFlag = 0
	submitSM.EsmClass = 0

	return submitSM
}
