package simprocnew

import (
	"fmt"
	"strings"

	"gitlab.com/ics_cinnamon/voicegateway/icserror"
	"gitlab.com/ics_cinnamon/voicegateway/icslog"
	"gitlab.com/ics_cinnamon/voicegateway/icsnet"
	"gitlab.com/ics_cinnamon/voicegateway/sim/simproc"
	"gitlab.com/ics_cinnamon/voicegateway/sim/siptemplate"
)

type SipCallFunc func(*SimCall)

type SimCall struct {
	sipType string
	cbFunc  SipCallFunc
}

// s.Id = sessionid, id = sim agent id
func NewSIPSignal(sipType string, sessionId int, id string, toid string, ra icsnet.IcsNetAddr, callid string, ip string, rTPTxPort int, laddr *icsnet.IcsNetAddr, rsaddr *icsnet.IcsNetAddr, lsaddr *icsnet.IcsNetAddr, localSIPUDP *icsnet.IcsUDPNet, buf []byte, rlen int) *icserror.IcsError {
	var sendTmpl string
	var bye200 *icserror.IcsError
	var sendMsg string
	tmpl := siptemplate.GetTemplate()
	l := icslog.GetIcsLog()

	if strings.ToUpper(sipType) == "REGI" {
		// fmt.Println("#### Received REGI ")
		p := simproc.NewSIPProc(buf[:rlen])
		from := p.SIPHeader.From
		id = strings.Split(strings.Split(from, "@")[0], ":")[1]

		sendTmpl = tmpl.String(siptemplate.REGI_ID)
		sendMsg = fmt.Sprintf(sendTmpl,
			id, //start line
			id, //from
			callid,
			id, //content
		)
		WriteSIP(sipType, sessionId, ra, callid, ip, rTPTxPort, laddr, rsaddr, lsaddr, sendMsg, localSIPUDP)
	} else {
		switch strings.ToUpper(sipType) {
		case "INVITE":
			sendTmpl = tmpl.String(siptemplate.INVITETMPL_ID)
			sendMsg = fmt.Sprintf(sendTmpl,
				id,        //start line
				id,        // from
				id,        // to
				callid,    //call id
				id,        //contact
				227,       //content-length
				ip,        //c=
				rTPTxPort, //o=
			)
		case "INVITE200":
		case "ACK":
			sendTmpl = tmpl.String(siptemplate.ACKTMPL_ID)
			sendMsg = fmt.Sprintf(sendTmpl,
				id,     //start line
				id,     //from
				id,     //to
				callid, //callid
				id,     //conatact
			)
		case "BYE":
			sendTmpl = tmpl.String(siptemplate.BYETMPL_ID)
			sendMsg = fmt.Sprintf(sendTmpl,
				id,     //start line
				id,     //from
				id,     //to
				callid, //call id
			)
		case "BYE200":
			sendTmpl = tmpl.String(siptemplate.OK200BYETMPL_ID)
			sendMsg = fmt.Sprintf(sendTmpl,
				id,     //from
				id,     //to
				callid, //callid
				id,     //contact
			)
		case "REFER":
		case "NOTIFY":
		case "NOTIFY200":
		}

		l.Printf(icslog.LOG_LEVEL_INFO, sessionId, "Call ID [%s]", callid)
		WriteSIP(sipType, sessionId, ra, callid, ip, rTPTxPort, laddr, rsaddr, lsaddr, sendMsg, localSIPUDP)
		if strings.ToUpper(sipType) != "ACK" && strings.ToUpper(sipType) != "BYE" {
			_, _, err := NewReadSIP(sessionId, callid, ip, rTPTxPort, ra, laddr, rsaddr, lsaddr, localSIPUDP)
			if err != nil {
				l.Printf(icslog.LOG_LEVEL_ERROR, sessionId, "Failed to recv SIP - %v", err)
				return err
			}
		}
	}
	if bye200 != nil {
		return bye200
	}

	return nil
}

func NewReadSIP(sessionId int, callid string, ip string, rTPTxPort int, ra icsnet.IcsNetAddr, laddr *icsnet.IcsNetAddr, rsaddr *icsnet.IcsNetAddr, lsaddr *icsnet.IcsNetAddr, localSIPUDP *icsnet.IcsUDPNet) ([]byte, int, *icserror.IcsError) {
	l := icslog.GetIcsLog()
	buf, remAddr, rlen, siperr := localSIPUDP.ReadSIP()
	if siperr != nil {
		l.Printf(icslog.LOG_LEVEL_ERROR, sessionId, "Failed to recv SIP - %v", siperr)
		localSIPUDP.Close()
		return nil, 0, siperr
	} else {
		// fmt.Printf("####### Receved SIP Packet > \r\n%s \r\n", buf[:rlen])
		l.Printf(icslog.LOG_LEVEL_INFO, sessionId, "Recved SIP Packet [%s:%d]->[%s:%d]>\n%s\n===================",
			remAddr.IP.String(), remAddr.Port, rsaddr.IPv4String, rsaddr.Port, buf[:rlen])
	}
	return buf, rlen, nil
}

func WriteSIP(sipType string, sessionId int, ra icsnet.IcsNetAddr, callid string, ip string, rTPTxPort int, laddr *icsnet.IcsNetAddr, rsaddr *icsnet.IcsNetAddr, lsaddr *icsnet.IcsNetAddr, sendMsg string, localSIPUDP *icsnet.IcsUDPNet) *icserror.IcsError {
	l := icslog.GetIcsLog()
	l.Printf(icslog.LOG_LEVEL_INFO, sessionId, "Call ID [%s]", callid)
	// fmt.Println("send msg", sendMsg)

	_, werr := localSIPUDP.Write([]byte(sendMsg))
	if werr != nil {
		l.Printf(icslog.LOG_LEVEL_ERROR, sessionId, "Failed to send SIP - %v", werr)
		localSIPUDP.Close()
		return werr
	} else {
		l.Printf(icslog.LOG_LEVEL_INFO, sessionId, "Send SIP Packet [%s:%d]->[%s:%d]>\n%s\n===================",
			ip, lsaddr.Port, rsaddr.IPv4String, rsaddr.Port, sendMsg)
		return nil
	}
}
