package fm

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

	"be.ems/lib/config"
	"be.ems/lib/dborm"
	"be.ems/lib/log"
	"github.com/linxGnu/gosmpp"
	"github.com/linxGnu/gosmpp/data"
	"github.com/linxGnu/gosmpp/pdu"
)

func AlarmSMSForward(alarmData *Alarm) error {
	switch config.GetYamlConfig().Alarm.SMProxy {
	case "sms":
		users, err := AlarmForwardBySMS(alarmData)
		writeLog(alarmData, users, "SMS", err)
		return err
	case "smsc":
		users, err := AlarmForwardBySMPP(alarmData)
		writeLog(alarmData, users, "SMS", err)
		return err
	default:
		users, err := AlarmForwardBySMPP(alarmData)
		writeLog(alarmData, users, "SMS", err)
		return err
	}
}

func AlarmForwardBySMS(alarmData *Alarm) (string, 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
	}
	userList := strings.Join(*toUsers, ",")

	// 短信相关参数
	params := url.Values{}
	params.Set("PhoneNumbers", userList)
	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 userList, err
	}

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

	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Error("Failed to send request:%v", err)
		return userList, err
	}
	defer resp.Body.Close()

	// 解析响应
	switch resp.StatusCode {
	case http.StatusOK, http.StatusAccepted, http.StatusNoContent, http.StatusCreated:
		return userList, nil
	default:
		log.Error(fmt.Errorf("failed to send SMS: %s(Code=%d)", resp.Status, resp.StatusCode))
		return userList, err
	}
}

var smsForward = &(config.GetYamlConfig().Alarm.SMSCForward)

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

	if smsForward == nil {
		err := errors.New("smsForward configuration is nil")
		log.Error(err)
		return "", err
	}
	userList := smsForward.MobileList
	auth := gosmpp.Auth{
		SMSC:       smsForward.SMSCAddr,
		SystemID:   smsForward.SystemID,
		Password:   smsForward.Password,
		SystemType: smsForward.SystemType,
	}

	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("Failed to create SMPP new session:", err)
		return userList, err
	}
	// defer func() {
	// 	if err := trans.Close(); err != nil {
	// 		log.Error(err)
	// 	}
	// }()

	message := "Alarm Notification: " + alarmData.AlarmTitle +
		" from " + alarmData.NeType + "_" + alarmData.NeId +
		" at " + alarmData.EventTime
	users := strings.Split(userList, ",")
	for _, user := range users {
		sm, err := newSubmitSM(user, message)
		if err != nil {
			log.Errorf("Failed to newSubmitSM %s short message: %v", user, err)
			writeLog(alarmData, user, "SMS", err)
			continue
		}
		if err = trans.Transceiver().Submit(sm); err != nil {
			log.Errorf("Failed to Submit %s short message: %v", user, err)
			writeLog(alarmData, user, "SMS", err)
			continue
		}
		writeLog(alarmData, user, "SMS", nil)
	}

	return userList, nil
}

func writeLog(alarmData *Alarm, toUser, forwardBy string, err error) error {
	var result string
	if err == nil {
		result = "SMS sent successfully"
	} else {
		result = err.Error()
	}
	forwardLog := &dborm.AlarmForwardLog{
		NeType:     alarmData.NeType,
		NeID:       alarmData.NeId,
		AlarmID:    alarmData.AlarmId,
		AlarmTitle: alarmData.AlarmTitle,
		AlarmSeq:   alarmData.AlarmSeq,
		EventTime:  alarmData.EventTime,
		Interface:  forwardBy,
		ToUser:     toUser,
		OperResult: result,
	}

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

func newSubmitSM(phoneNumber string, message string) (*pdu.SubmitSM, error) {
	// build up submitSM
	srcAddr := pdu.NewAddress()
	srcAddr.SetTon(5)
	srcAddr.SetNpi(0)
	err := srcAddr.SetAddress(smsForward.ServiceNumber)
	if err != nil {
		return nil, err
	}
	destAddr := pdu.NewAddress()
	destAddr.SetTon(1)
	destAddr.SetNpi(1)
	err = destAddr.SetAddress(phoneNumber)
	if err != nil {
		return nil, err
	}
	submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
	submitSM.SourceAddr = srcAddr
	submitSM.DestAddr = destAddr
	dataCoding := data.FromDataCoding(smsForward.DataCoding)
	err = submitSM.Message.SetMessageWithEncoding(message, dataCoding)
	if err != nil {
		return nil, err
	}
	submitSM.ProtocolID = 0
	submitSM.RegisteredDelivery = 1
	submitSM.ReplaceIfPresentFlag = 0
	submitSM.EsmClass = 0

	return submitSM, nil
}

// const (
// 	// Short message data coding type
// 	SMS_CODING_GSM7BIT byte = iota
// 	SMS_CODING_ASCII
// 	SMS_CODING_BINARY8BIT1
// 	SMS_CODING_LATIN1
// 	SMS_CODING_BINARY8BIT2
// 	SMS_CODING_NODEF
// 	SMS_CODING_CYRILLIC
// 	SMS_CODING_HEBREW
// 	SMS_CODING_UCS2
// )

// var codingMap = map[byte]data.Encoding{
// 	SMS_CODING_GSM7BIT:     data.GSM7BIT,
// 	SMS_CODING_ASCII:       data.ASCII,
// 	SMS_CODING_BINARY8BIT1: data.BINARY8BIT1,
// 	SMS_CODING_LATIN1:      data.LATIN1,
// 	SMS_CODING_BINARY8BIT2: data.BINARY8BIT2,
// 	SMS_CODING_CYRILLIC:    data.CYRILLIC,
// 	SMS_CODING_HEBREW:      data.HEBREW,
// 	SMS_CODING_UCS2:        data.UCS2,
// }
