package icssessionmanager

import (
	"fmt"
	"os"
	"runtime/debug"
	"sync"

	"gitlab.com/cinnamon/voiceagent/icsconf"
	"gitlab.com/cinnamon/voiceagent/icserror"
	"gitlab.com/cinnamon/voiceagent/icsevent"
	"gitlab.com/cinnamon/voiceagent/icslog"
	"gitlab.com/cinnamon/voiceagent/icssvc"
)

type SessionManager struct {
	evtSystem []*icsevent.EventSystem
	sessions  []*IcsSession

	event *icsevent.EventH
}

var bigSession []*IcsSession

//var bigSession []*IcsSession
var onceSession sync.Once
var channelNum int

func getSessionInstance() []*IcsSession {
	onceSession.Do(func() {
		l := icslog.GetIcsLog()
		conf := icsconf.GetIcsConfig()

		bigSession = make([]*IcsSession, channelNum)

		for iter := 0; iter < channelNum; iter++ {
			bigSession[iter] = new(IcsSession)
			bigSession[iter].m = &sync.Mutex{}
			bigSession[iter].ID = iter
			//bigSession[iter].goroutineID = goid()
			bigSession[iter].isStart = 0
			//bigSession[iter].lastTimestamp = time.Now()

			bigSession[iter].eventSystem = icsevent.GetMyEventSystem(iter)
			//bigSession[iter].Init(iter)

			bigSession[iter].isBotStart = false
			bigSession[iter].isSTTStart = false

			if conf.AgentConfig[iter].Value {
				defer func() {
					if err := recover(); err != nil {
						switch v := err.(type) {
						case error:
							icserror.ICSERRNETNotConnectError.SetError(v)
							l.Printf(icslog.LOG_LEVEL_WARN, iter, "PANIC! %s\n%s", icserror.ICSERRNETNotConnectError.GetError().Error(), string(debug.Stack()))
							fmt.Println(string(debug.Stack()), "\nFailed to initialize Voice Agent. EXIT!")
							os.Exit(1)
						default:
							l.Print(icslog.LOG_LEVEL_WARN, iter, icserror.ICSERRNETNotConnectError.GetMessage())
						}
					}
				}()

				/*
					//listen call signal port
					if conf.AgentConfig[iter].CSConfig.Port != 0 {
						csladdr := icsnet.NewNetAddrWithIPPort("0.0.0.0", conf.AgentConfig[iter].CSConfig.Port)
						bigSession[iter].CallSignalNeter = icsnet.NewTCP(&csladdr, nil)
						cserr := bigSession[iter].CallSignalNeter.Listen()
						if cserr != nil {
							l.Printf(icslog.LOG_LEVEL_FATAL, iter, "Port[%s] Listen Failure - %s", csladdr, cserr.GetError())
						} else {
							l.Printf(icslog.LOG_LEVEL_INFO, iter, "Call signal port open - %s", csladdr)
						}
					}
				*/

				/*
					//listen voice port
					vraddr := icsnet.NewNetAddrWithIPPort("0.0.0.0", conf.AgentConfig[iter].Port)
					bigSession[iter].VoiceNeter = icsnet.NewUDP(&vraddr, nil)
					lerr := bigSession[iter].VoiceNeter.Listen()
					if lerr != nil {
						l.Printf(icslog.LOG_LEVEL_FATAL, iter, "Port[%s] Listen Failure - %s", vraddr, lerr.GetError())
					} else {
						l.Printf(icslog.LOG_LEVEL_INFO, iter, "Voice port open - %s", vraddr)
					}
				*/
			}
		}
	})

	return bigSession
}

func NewSessionManager() *SessionManager {
	svc := icssvc.NewService()
	channelNum = svc.GetIcsConfig().GetChannelNum()
	//icsevent.SetConfig(svc.GetIcsConfig())

	sm := new(SessionManager)
	icsevent.SetChannelNum(channelNum)
	sm.evtSystem = icsevent.GetEvtSystemInstance()
	sm.sessions = getSessionInstance()

	//EventH. Create Event Array
	sm.event = icsevent.NewEventH()

	return sm
}

func (sm *SessionManager) Load() *icserror.IcsError {
	//l := icslog.GetIcsLog()

	sm.event.Init()

	//for iter, session := range sm.sessions {
	for _, session := range sm.sessions {
		//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "333 %d", iter)
		//l.Printf(icslog.LOG_LEVEL_DEBUG2, -1, "444 %d", session.ID)
		go session.Run()
	}

	return nil
}