package service

import (
	"bytes"
	"fmt"
	"strings"
	tt "text/template"
	"time"

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

	"be.ems/src/framework/config"
	"be.ems/src/framework/logger"
	"be.ems/src/framework/utils/date"
	"be.ems/src/framework/utils/parse"
	neDataModel "be.ems/src/modules/ne_data/model"
)

var smscSession *gosmpp.Session

// connSM 连接smsc
func connSM() *gosmpp.Session {
	if smscSession != nil {
		return smscSession
	}
	smscAddr := fmt.Sprint(config.Get("notification.smsc.addr"))
	systemType := fmt.Sprint(config.Get("notification.smsc.systemtype"))
	systemID := fmt.Sprint(config.Get("notification.smsc.systemid"))
	password := fmt.Sprint(config.Get("notification.smsc.password"))
	// 建立连接
	session, err := gosmpp.NewSession(
		gosmpp.TXConnector(gosmpp.NonTLSDialer, gosmpp.Auth{
			SMSC:       smscAddr,
			SystemID:   systemID,
			Password:   password,
			SystemType: systemType,
		}),
		gosmpp.Settings{
			ReadTimeout: 2 * time.Second,
			OnSubmitError: func(_ pdu.PDU, err error) {
				logger.Errorf("failed to smpp submit error: %s", err.Error())
			},
			OnRebindingError: func(err error) {
				logger.Errorf("failed to smpp rebinding error: %s", err.Error())
			},
		}, -1)
	if err != nil {
		logger.Errorf("failed to create smpp new session error: %s", err.Error())
		return nil
	}
	// defer session.Close()
	smscSession = session
	return smscSession
}

// newSubmitSM 构建短信提交
func newSubmitSM(destSM string, message string) (*pdu.SubmitSM, error) {
	dataCoding := parse.Number(config.Get("notification.smsc.coding"))
	enc := data.FromDataCoding(byte(dataCoding))
	srcSM := fmt.Sprint(config.Get("notification.smsc.servicenumber"))
	// 源地址
	srcAddr := pdu.NewAddress()
	srcAddr.SetTon(5)
	srcAddr.SetNpi(0)
	err := srcAddr.SetAddress(srcSM)
	if err != nil {
		return nil, err
	}
	destAddr := pdu.NewAddress()
	destAddr.SetTon(1)
	destAddr.SetNpi(1)
	err = destAddr.SetAddress(destSM)
	if err != nil {
		return nil, err
	}
	// build up submitSM
	submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
	submitSM.SourceAddr = srcAddr
	submitSM.DestAddr = destAddr
	if err = submitSM.Message.SetMessageWithEncoding(message, enc); err != nil {
		return nil, err
	}
	submitSM.ProtocolID = 0
	submitSM.RegisteredDelivery = 1
	submitSM.ReplaceIfPresentFlag = 0
	submitSM.EsmClass = 0
	return submitSM, nil
}

// SMSCAlarm 发告警短信
func SMSCAlarm(a neDataModel.Alarm, neIP string) error {
	mobileList := fmt.Sprint(config.Get("notification.smsc.list"))
	if len(mobileList) == 0 {
		return fmt.Errorf("smsc list is empty")
	}

	// 模板
	textBodyTemplate := `Alarm Notification
	Sequence: {{.AlarmSeq}}, 
	NE Name: {{.NeName}}
	NE IP: {{.NeIp}}
	Title: {{.AlarmTitle}}
	Severity: {{.OrigSeverity}}
	Event Time: {{.AlarmTime}}
	Alarm Status: {{.AlarmStatus}}
	Automatic sent by OMC, please do not reply!`
	textTpl, err := tt.New("texttpl").Parse(textBodyTemplate)
	if err != nil {
		return fmt.Errorf("SMSCAlarm alarmId:%s fail %s", a.AlarmId, err.Error())
	}
	// 参数值
	data := map[string]any{
		"AlarmSeq":     a.AlarmSeq,
		"NeName":       a.NeName,
		"NeIp":         neIP,
		"AlarmTitle":   a.AlarmTitle,
		"OrigSeverity": a.OrigSeverity,
		"AlarmTime":    date.ParseDateToStr(a.EventTime, time.RFC3339),
		"AlarmStatus":  a.AlarmStatus,
	}
	buffer := bytes.NewBuffer(nil)
	if err := textTpl.Execute(buffer, data); err != nil {
		return fmt.Errorf("EmailAlarm Execute alarmId:%s fail %s", a.AlarmId, err.Error())
	}
	textStr := buffer.String()

	// 发送短信
	err = SMSCSendText(textStr, strings.Split(mobileList, ","))
	if err != nil {
		return fmt.Errorf("EmailAlarm alarmId:%s fail %s", a.AlarmId, err.Error())
	}
	return err
}

// SMSCSendText 发送文本短信
func SMSCSendText(textStr string, toMobileArr []string) error {
	enable := parse.Boolean(config.Get("notification.smsc.enable"))
	if !enable {
		return fmt.Errorf("smsc notification not enable")
	}
	sm := connSM()
	if sm == nil {
		return fmt.Errorf("smpp new session create failed")
	}

	errArr := []string{}
	for _, v := range toMobileArr {
		submitSM, err := newSubmitSM(v, textStr)
		if err != nil {
			errArr = append(errArr, err.Error())
			continue
		}
		if err = sm.Transceiver().Submit(submitSM); err != nil {
			errArr = append(errArr, err.Error())
			continue
		}
	}
	if len(errArr) > 0 {
		return fmt.Errorf("%s", strings.Join(errArr, ","))
	}
	return nil
}
