package icssessionmanager

import (
	"strconv"
	"strings"
	"time"

	"gitlab.com/cinnamon/voiceagent/icserror"
	"gitlab.com/cinnamon/voiceagent/icslog"
	"gitlab.com/cinnamon/voiceagent/icsmediaconv"
	"gitlab.com/cinnamon/voiceagent/icsnet"
	"gitlab.com/cinnamon/voiceagent/icspacketparser"
	"gitlab.com/cinnamon/voiceagent/icssvc"
	"gitlab.com/cinnamon/voiceagent/recorddata/writecallsignal"
)

func (s *IcsSession) analyzeSIP(sip *icspacketparser.SIP) *icserror.IcsError {
	// fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>")
	// fmt.Println("sip.Method", sip.Method)
	// fmt.Println("sip.Version", sip.Version)
	// fmt.Println("sip.Headers", sip.Headers)
	// fmt.Println("sip.Source", sip.Source)

	// fmt.Printf("%+v\n", sip)
	//fmt.Println(">>>>>>>>>>>>>>>>>>>>>>> sip.Method", sip.Method)

	l := icslog.GetIcsLog()
	// fmt.Println(">>>>>>>>>>>>>>>>>>>>>>> sip.Method", sip.Method)

	if sip.Method == icspacketparser.ICS_SIP_METHOD_INVITE {
		s.setSrcPort(sip)

		payload, err := s.setSDPMediaPayload(sip)
		if err != nil {
			return icserror.ICSERRSDPAudiotagPortValue
		} else {
			s.invitePayloads = payload
		}
	} else if strings.Contains(sip.Cseq, " INVITE") {
		s.setDstPort(sip)
	}

	if sip.Method == icspacketparser.ICS_SIP_METHOD_SIP20 && !s.isFoundPayload {
		// fmt.Println(">>>>>>>>>>>>>>> ICS_SIP_METHOD_SIP20", sip.ResType, sip.ContentType, sip.ContentLength)
		if strings.Contains(sip.ContentType, "sdp") && sip.ContentLength > 0 {
			payload, err := s.compareSDPMediaPayload(sip)
			if err != nil {
				return icserror.ICSERRSDPAudiotagPortValue
			} else {
				s.isFoundPayload = true
				s.payloadType = icspacketparser.PayloadType(payload)
				//fmt.Println("s.payload >>>>>>>>>>>>>>>", s.payloadType)

				//create media decoder
				var cerr *icserror.IcsError
				s.TxConverter, cerr = icsmediaconv.NewConverter(s.ID, s.payloadType)
				if cerr != nil {
					//s.isFoundPayload = false
					//cerr.Print()
					l.Printf(icslog.LOG_LEVEL_FATAL, s.ID, "Failed to New Tx Converter-%v", cerr)
					s.SendVoiceGatewayByeSignal()
					return cerr
				} else {
					l.Print(icslog.LOG_LEVEL_INFO, s.ID, "New Tx Converter(Decoder)")
				}
				s.RxConverter, cerr = icsmediaconv.NewConverter(s.ID, s.payloadType)
				if cerr != nil {
					//s.isFoundPayload = false
					l.Printf(icslog.LOG_LEVEL_FATAL, s.ID, "Failed to New Rx Converter-%v", cerr)
					s.SendVoiceGatewayByeSignal()
					return cerr
				} else {
					l.Print(icslog.LOG_LEVEL_INFO, s.ID, "New Rx Converter(Decoder)")
				}

				//init VoiceAgent net
				conf := icssvc.GetServiceStatus().GetIcsConfig()
				if conf != nil {
					//set call signal remote addr
					csraddr := icsnet.NewNetAddrWithIPPort("127.0.0.1", 1111)
					csladdr := icsnet.NewNetAddrWithIPPort("127.0.0.1", 2222)
					//csraddr := icsnet.NewNetAddrWithIPPort(conf.VoiceAgentConfig.AgentAddr.VoiceAgentIP, conf.VoiceAgentConfig.AgentAddr.CallSignalPort)
					//csladdr := icsnet.NewNetAddrWithIPPort(conf.VoiceAgentConfig.MyAddr.ServerIP, conf.VoiceAgentConfig.MyAddr.ServerPort)

					//set Voice remote addr
					vraddr := icsnet.NewNetAddrWithIPPort("127.0.0.1", 3333)
					//vraddr := icsnet.NewNetAddrWithIPPort(conf.VoiceAgentConfig.AgentAddr.VoiceAgentIP, conf.VoiceAgentConfig.AgentAddr.VoicePort)
					//vladdr := icsnet.NewNetAddrWithIPPort(conf.VoiceAgentConfig.MyAddr.ServerIP, conf.VoiceAgentConfig.MyAddr.BasePort)

					s.VoiceNeter = icsnet.NewUDP(nil, &vraddr)
					//s.VoiceNeter = icsnet.NewUDP(&vladdr, &vraddr)
					conerr := s.VoiceNeter.Connect()
					if conerr != nil {
						l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Error init Voice Neter[%s->%s]-%v", s.VoiceNeter.LocalAddr().String(), vraddr.String(), conerr.GetError())
						s.SendVoiceGatewayByeSignal()
						return conerr
					}
					l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Voice(UDP) Connected to VoiceAgent[%s->%s]", s.VoiceNeter.LocalAddr().String(), vraddr.String())

					//send call signal data to VoiceAgent
					defer func() {
						if err := recover(); err != nil {
							l.Print(icslog.LOG_LEVEL_WARN, s.ID, icserror.ICSERRNETNotConnectError.GetMessage())
						}
					}()
					var inout string = "O"
					if s.GetDirection() {
						inout = "I"
					}
					callsignal := writecallsignal.NewCallSignalData()
					//callsignal := recorddata.NewCallSignalData()
					//s.StartTimeStamp = time.Now().UnixNano() / 1e6
					s.StartTimeStamp = time.Now().UnixNano()
					callsignal.SetData(s.ChannelID, s.ServerID, s.Station, "CUSTID", s.StartTimeStamp, 0, "S", inout)
					wlen, werr := icsnet.SendCallSignal(&csladdr, &csraddr, callsignal.GetData())
					if werr == nil {
						l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Transmitted Call-Start signal to VoiceAgent(%d)", wlen)
					}
				}
			}
		}
	}

	return nil
}

func (s *IcsSession) setSrcPort(sip *icspacketparser.SIP) *icserror.IcsError {
	if sip.Content == nil {
		//error 처리 invite인데, sdp 데이터가 없음
		return icserror.ICSERRINVITERequired
	} else {
		// fmt.Println("sdpMedias", *sip.Content.Media)
		port, err := s.findSDPMediaAudioPort(sip)
		if err != nil {
			return icserror.ICSERRSDPAudiotagPortValue
		} else {
			s.srcPort = port
		}
	}
	return nil
}

func (s *IcsSession) setDstPort(sip *icspacketparser.SIP) *icserror.IcsError {
	// fmt.Println(">>>>>>>>>>>>>>>>>>>>>>> sip.Cseq", sip.Cseq, sip.Method)
	if sip.Method == icspacketparser.ICS_SIP_METHOD_SIP20 && sip.ResType == "200" {
		if sip.Content == nil {
			//error 처리 INVITE처리의 200 OK인데, sdp 데이터가 없음
			return icserror.ICSERR200OKRequired
		} else {
			// fmt.Println("sdpMedias", *sip.Content.Media)
			port, err := s.findSDPMediaAudioPort(sip)
			if err != nil {
				return icserror.ICSERRSDPAudiotagPortValue
			} else {
				s.dstPort = port
			}
		}
	} else if sip.Method == icspacketparser.ICS_SIP_METHOD_BYE {
		//fmt.Println(">>>>>>>>>>> haup up event")
		// s.RemoveSession()
	}
	return nil
}

func (s *IcsSession) findSDPMediaAudioPort(sip *icspacketparser.SIP) (int, *icserror.IcsError) {
	for _, value := range *sip.Content.Media {
		if strings.Contains(value.MediaDescription, "audio ") {
			arrSdpMedia := strings.Split(value.MediaDescription, " ")
			port, err := strconv.Atoi(arrSdpMedia[1])
			if err != nil {
				return -1, icserror.ICSERRSDPAudiotagPortValue
			} else {
				//fmt.Println(">>>>>>>>>>>>>>>>>>>>>>> port", port)
				return port, nil
			}
		} else {
			return -1, icserror.ICSERRNotFoundSdpMedia
		}
	}
	return -1, icserror.ICSERRNotFoundSdpMedia
}

func (s *IcsSession) setSDPMediaPayload(sip *icspacketparser.SIP) ([]string, *icserror.IcsError) {
	for _, value := range *sip.Content.Media {
		if strings.Contains(value.MediaDescription, "audio ") {
			//fmt.Println("value.Payload >>>>>>>>>>>", value.Payload)
			return value.Payload, nil
		} else {
			return nil, icserror.ICSERRNotFoundSdpMedia
		}
	}
	return nil, icserror.ICSERRNotFoundSdpMedia
}

func (s *IcsSession) compareSDPMediaPayload(sip *icspacketparser.SIP) (int, *icserror.IcsError) {
	for _, value := range *sip.Content.Media {
		for _, thisPayload := range value.Payload {
			for _, invitePayload := range s.invitePayloads {
				if thisPayload == invitePayload {
					payload, err := strconv.Atoi(thisPayload)
					if err != nil {
						return -1, icserror.ICSERRSDPAudiotagPortValue
					} else {
						return payload, nil
					}
				}
			}
		}
	}
	return -1, icserror.ICSERRNotFoundSdpMedia
}
