package icsconf

import (
	"encoding/xml"
	"fmt"
	"os"
	"strings"

	"gitlab.com/cinnamon/voiceagent/icserror"
)

type IcsConfig struct {
	XMLName          xml.Name         `xml:"ICSVB"`
	Version          string           `xml:"version,attr"`
	InfoConfig       InfoConfig       `xml:"INFO"`
	LicenseConfig    LicenseConfig    `xml:"LICENSE"`
	LogConfig        LogConfig        `xml:"LOG"`
	ServerConfig     ServerConfig     `xml:"SERVER"`
	VoiceConfig      VoiceConfig      `xml:"VOICESAVE"`
	HeartBeat        HeartBeatConfig  `xml:"HEARTBEAT"`
	HTTPConfig       HTTPConfig       `xml:"HTTP"`
	STTConfig        STTConfig        `xml:"STT"`
	TTSConfig        TTSConfig        `xml:"TTS"`
	CommandConfig    CommandConfig    `xml:"COMMAND"`    //bot command
	VGWCommandConfig VGWCommandConfig `xml:"VGWCOMMAND"` //voicegateway bot command
	AgentConfig      []AgentConfig    `xml:"AGENT"`
	SessionExpired   SessionExpired   `xml:"SESSIONEXPIRED"`
	DtmfEndSignal    DtmfEndSignal    `xml:"DTMFEND"`
	ExceptTest       Except           `xml:"EXCEPT"` // 예외처리
	HomeDir          string
	ScenarioConfig   ScenarioConfig `xml:"SCENARIOORDER"`
	TimeSleep        TimeSleep      `xml:"TIMESLEEP"`
}

type InfoConfig struct {
	TenentID string `xml:"TENENTID"`
	ServerID int    `xml:"SERVERID"`
	ServerIP string `xml:"SERVERIP"`
}

type ServerConfig struct {
	CSConfig CSConfig `xml:"CALLSIGNAL"`
}

type SessionExpired struct {
	SSec int `xml:"sec,attr"`
}

type DtmfEndSignal struct {
	Signal string `xml:"signal,attr"`
}

type TimeSleep struct {
	Value     bool `xml:"value,attr"`
	TimeSleep int  `xml:"sec,attr"`
}

type VoiceConfig struct {
	SaveYn     string     `xml:"SAVEYN"`
	Path       string     `xml:"PATH"`
	DelVConfig DelVConfig `xml:"DELVPERIOD"`
}

type DelVConfig struct {
	DelVDay  int `xml:"vday,attr"`
	DelVHour int `xml:"vhour,attr"`
}

type HeartBeatConfig struct {
	Value    bool   `xml:"value,attr"`
	Interval int    `xml:"interval,attr"`
	SrcIP    string `xml:"srcIP,attr"`
	Port     int    `xml:"port,attr"`
}

type HTTPConfig struct {
	Value bool   `xml:"value,attr"`
	Port  int    `xml:"port,attr"`
	SrcIP string `xml:"srcIP,attr"`
}

type STTConfig struct {
	Value bool   `xml:"value,attr"`
	Name  string `xml:"name,attr"`
	Port  int    `xml:"port,attr"`
	SrcIP string `xml:"srcIP,attr"`
}

type TTSConfig struct {
	Value bool   `xml:"value,attr"`
	Name  string `xml:"name,attr"`
	Port  int    `xml:"port,attr"`
	SrcIP string `xml:"srcIP,attr"`
}

type CommandConfig struct {
	Value bool   `xml:"value,attr"`
	Port  int    `xml:"port,attr"`
	SrcIP string `xml:"srcIP,attr"`
}

type VGWCommandConfig struct {
	Value bool   `xml:"value,attr"`
	IP    string `xml:"ip,attr"`
	Port  int    `xml:"port,attr"`
}

type AgentConfig struct {
	Name      string    `xml:"name,attr"`
	Value     bool      `xml:"value,attr"`
	Transport string    `xml:"transport,attr"`
	Port      int       `xml:"port,attr"`
	Action    string    `xml:"action,attr"`
	BotConfig BotConfig `xml:"BOT"`
	WSConfig  WSConfig  `xml:"WEBSOCKET"`
}

type BotConfig struct {
	Action  string `xml:"action,attr"`
	CustTel string `xml:"custtel,attr"`
	IP      string `xml:"ip,attr"`
	Port    int    `xml:"port,attr"`
	URL1    string `xml:"url1,attr"`
	URL2    string `xml:"url2,attr"`
}

type WSConfig struct {
	IP   string `xml:"ip,attr"`
	Port int    `xml:"port,attr"`
	Path string `xml:"path,attr"`
}

type CSConfig struct {
	Port int `xml:"port,attr"`
}

type LicenseConfig struct {
	Key      string `xml:"KEY"`
	Channels int    `xml:"CHANNELS"`
	Expire   int    `xml:"EXPIRE"`
}

type LogConfig struct {
	Path         string       `xml:"PATH"`
	Disklimit    int          `xml:"DISKLIMIT"`
	Level        string       `xml:"LEVEL"`
	Output       string       `xml:"OUTPUT"`
	RotateConfig RotateConfig `xml:"ROTATE"`
	DelConfig    DelConfig    `xml:"DELPERIOD"`
	HomeDir      string
}

type DelConfig struct {
	DelDay  int `xml:"day,attr"`
	DelHour int `xml:"hour,attr"`
}

type Except struct {
	TestInfo TestInfo `xml:"TESTINFO"`
}

type TestInfo struct {
	Value        bool   `xml:"value,attr"`
	Type         string `xml:"type,attr"`
	ResultCode   int    `xml:"resultCode,attr"`
	Token        string `xml:"token,attr"`
	Action       string `xml:"action,attr"`
	Announcement string `xml:"announcement,attr"`
	Bargein      string `xml:"bargein,attr"`
	Recodingfile string `xml:"recodingfile,attr"`
	Sttmaxtime   int    `xml:"sttmaxtime,attr"`
}

type RotateConfig struct {
	Size  string `xml:"size,attr"`
	Num   string `xml:"num,attr"`
	YesNo string `xml:"yesno,attr"`
}

type CaptureConfig struct {
	Device []string `xml:"DEVICE"`
	Filter string   `xml:"FILTER"`
}

type PbxConfig struct {
	PbxIp   string `xml:"IP"`
	PbxPort int    `xml:"PORT"`
}

type VoiceAgentConfig struct {
	AgentAddr AgentAddr `xml:"AGENT"`
	MyAddr    MyAddr    `xml:"SERVER"`
}

type AgentAddr struct {
	CallSignalPort int    `xml:"callsignalport,attr"`
	VoicePort      int    `xml:"voiceport,attr"`
	VoiceAgentIP   string `xml:",chardata"`
}

type MyAddr struct {
	ServerPort int    `xml:"port,attr"`
	BasePort   int    `xml:"baseport,attr"`
	PortRange  int    `xml:"range,attr"`
	ServerIP   string `xml:",chardata"`
}

var gIcsConfig *IcsConfig

func OpenConfig(ConfigFileName string, homeDir string) (*IcsConfig, *icserror.IcsError) {
	fi, err := os.Open(ConfigFileName)
	if err != nil {
		icserror.ICSERRCONFOpenFile.SetError(err)
		return nil, icserror.ICSERRCONFOpenFile
	}
	defer fi.Close()

	FI, _ := os.Stat(ConfigFileName)
	FileLength := FI.Size()

	configdata := make([]byte, FileLength)
	cnt, err := fi.Read(configdata)
	if cnt == 0 || err != nil {
		icserror.ICSERRCONFFileNotFound.SetError(err)
		return nil, icserror.ICSERRCONFFileNotFound
	}

	conf := IcsConfig{}
	conf.HomeDir = homeDir

	err = xml.Unmarshal([]byte(configdata), &conf)
	if err != nil {
		icserror.ICSERRCONFUnmarshal.SetError(err)
		return nil, icserror.ICSERRCONFUnmarshal
	}

	if !strings.HasPrefix(conf.LogConfig.Path, "/") {
		conf.LogConfig.Path = fmt.Sprintf("%s/%s", homeDir, conf.LogConfig.Path)
	}
	//default setting
	if conf.LogConfig.DelConfig.DelDay == 0 {
		conf.LogConfig.DelConfig.DelHour = 90
	}
	if conf.LogConfig.DelConfig.DelHour == 0 {
		conf.LogConfig.DelConfig.DelHour = 2
	}
	if conf.VoiceConfig.DelVConfig.DelVDay == 0 {
		conf.VoiceConfig.DelVConfig.DelVDay = 90
	}
	if conf.VoiceConfig.DelVConfig.DelVHour == 0 {
		conf.VoiceConfig.DelVConfig.DelVHour = 2
	}
	if conf.SessionExpired.SSec == 0 {
		conf.SessionExpired.SSec = 3600
	}
	if conf.DtmfEndSignal.Signal == "" {
		conf.DtmfEndSignal.Signal = "#"
	}
	conf.LogConfig.HomeDir = homeDir

	gIcsConfig = &conf

	return &conf, nil
}

func (c IcsConfig) GetChannelNum() int {
	return c.LicenseConfig.Channels
}

func (c IcsConfig) GetExpire() int {
	return c.LicenseConfig.Expire
}

func (c IcsConfig) GetHomeDir() string {
	return c.HomeDir
}

func (c IcsConfig) GetChannelID() string {
	return c.InfoConfig.TenentID
}

func (c IcsConfig) GetServerID() int {
	return c.InfoConfig.ServerID
}

//from LogConfig struct
func (c LogConfig) GetHomeDir() string {
	return c.HomeDir
}

func (c *IcsConfig) SetHomeDir(homeDir string) {
	c.HomeDir = homeDir
}

func GetIcsConfig() *IcsConfig {
	return gIcsConfig
}

func (c IcsConfig) ShowConfig() string {
	fmt.Printf("Licensed Channel number : %d\n", c.LicenseConfig.Channels)
	fmt.Printf("HeartBeat SrcIP : %s, Port : %d\n", c.HeartBeat.SrcIP, c.HeartBeat.Port)
	fmt.Printf("HTTP Port : %d, SrcIP : %s\n", c.HTTPConfig.Port, c.HTTPConfig.SrcIP)
	fmt.Printf("STT Port : %d, SrcIP : %s\n", c.STTConfig.Port, c.STTConfig.SrcIP)
	fmt.Printf("TTS Port : %d, SrcIP : %s\n", c.TTSConfig.Port, c.TTSConfig.SrcIP)
	fmt.Printf("Bot Command Port : %d, SrcIP : %s\n", c.CommandConfig.Port, c.CommandConfig.SrcIP)
	fmt.Printf("Voice Del Day : %d\n", c.VoiceConfig.DelVConfig.DelVDay)
	fmt.Printf("Voice Del Hour : %d\n", c.VoiceConfig.DelVConfig.DelVHour)
	fmt.Printf("Log Level : %s\n", c.LogConfig.Level)
	fmt.Printf("Log Path : %s\n", c.LogConfig.Path)
	fmt.Printf("Log Disk Space Size : %dMB\n", c.LogConfig.Disklimit)
	fmt.Printf("Log Del Day : %d\n", c.LogConfig.DelConfig.DelDay)
	fmt.Printf("Log Del Hour : %d\n", c.LogConfig.DelConfig.DelHour)
	fmt.Printf("Log Output : %s\n", c.LogConfig.Output)
	fmt.Printf("Log Rotate : %s\n", c.LogConfig.RotateConfig.YesNo)
	fmt.Printf("Log Rotate File Size : %sMB\n", c.LogConfig.RotateConfig.Size)
	fmt.Printf("Log Rotate File Number : %s\n\n", c.LogConfig.RotateConfig.Num)

	confmsg := fmt.Sprintf("Licensed Channel number : %d\n", c.LicenseConfig.Channels)
	confmsg += fmt.Sprintf("HeartBeat SrcIP : %s, Port : %d\n", c.HeartBeat.SrcIP, c.HeartBeat.Port)
	confmsg += fmt.Sprintf("HTTP Port : %d, SrcIP : %s\n", c.HTTPConfig.Port, c.HTTPConfig.SrcIP)
	confmsg += fmt.Sprintf("STT Port : %d, SrcIP : %s\n", c.STTConfig.Port, c.STTConfig.SrcIP)
	confmsg += fmt.Sprintf("TTS Port : %d, SrcIP : %s\n", c.TTSConfig.Port, c.TTSConfig.SrcIP)
	confmsg += fmt.Sprintf("Bot Command Port : %d, SrcIP : %s\n", c.CommandConfig.Port, c.CommandConfig.SrcIP)
	confmsg += fmt.Sprintf("Voice Del Day : %d\n", c.VoiceConfig.DelVConfig.DelVDay)
	confmsg += fmt.Sprintf("Voice Del Hour : %d\n", c.VoiceConfig.DelVConfig.DelVHour)
	confmsg += fmt.Sprintf("Log Level : %s\n", c.LogConfig.Level)
	confmsg += fmt.Sprintf("Log Path : %s\n", c.LogConfig.Path)
	confmsg += fmt.Sprintf("Log Disk Space Size : %dMB\n", c.LogConfig.Disklimit)
	confmsg += fmt.Sprintf("Log Del Day : %d\n", c.LogConfig.DelConfig.DelDay)
	confmsg += fmt.Sprintf("Log Del Hour : %d\n", c.LogConfig.DelConfig.DelHour)
	confmsg += fmt.Sprintf("Log Output : %s\n", c.LogConfig.Output)
	confmsg += fmt.Sprintf("Log Rotate : %s\n", c.LogConfig.RotateConfig.YesNo)
	confmsg += fmt.Sprintf("Log Rotate File Size : %sMB\n", c.LogConfig.RotateConfig.Size)
	confmsg += fmt.Sprintf("Log Rotate File Number : %s\n\n", c.LogConfig.RotateConfig.Num)

	return confmsg
}

type ScenarioConfig struct {
	Order      []string `xml:"method,attr"`
	Value      []string `xml:"value,attr"`
	BargeIn    []string `xml:"bargeIn,attr"`
	SttMaxTime []int    `xml:"sttMaxTime,attr"`
	TimeValue  []bool   `xml:"timeValue,attr"`
	TimeSleep  []int    `xml:"timesleep,attr"`
}

type SimConfig struct {
	XMLName           xml.Name          `xml:"SIMVC"`
	Version           string            `xml:"version,attr"`
	IsCaller          string            `xml:"ISCALLER"`
	Repeat            int               `xml:"REPEAT"`
	Channels          int               `xml:"CHANNELS"`
	TargetPhoneConfig TargetPhoneConfig `xml:"TARGET"`
	SimPhoneConfig    SimPhoneConfig    `xml:"SIM"`
	LogConfig         LogConfig         `xml:"LOG"`
	HomeDir           string
}

type TargetPhoneConfig struct {
	TargetIP string `xml:"ip,attr"`
	SIPPort  int    `xml:"sipport,attr"`
	RTPPort  int    `xml:"rtpport,attr"`
}

type SimPhoneConfig struct {
	MYIP    string `xml:"myip,attr"`
	SIPPort int    `xml:"sipport,attr"`
	RTPPort int    `xml:"rtpport,attr"`
}

func OpenSimConfig(ConfigFileName string, homeDir string) (*SimConfig, *icserror.IcsError) {
	fi, err := os.Open(ConfigFileName)
	if err != nil {
		icserror.ICSERRCONFOpenFile.SetError(err)
		return nil, icserror.ICSERRCONFOpenFile
	}
	defer fi.Close()

	FI, _ := os.Stat(ConfigFileName)
	FileLength := FI.Size()

	configdata := make([]byte, FileLength)
	cnt, err := fi.Read(configdata)
	if cnt == 0 || err != nil {
		icserror.ICSERRCONFFileNotFound.SetError(err)
		return nil, icserror.ICSERRCONFFileNotFound
	}

	conf := SimConfig{}
	conf.HomeDir = homeDir

	err = xml.Unmarshal([]byte(configdata), &conf)
	if err != nil {
		icserror.ICSERRCONFUnmarshal.SetError(err)
		return nil, icserror.ICSERRCONFUnmarshal
	}
	if !strings.HasPrefix(conf.LogConfig.Path, "/") {
		conf.LogConfig.Path = fmt.Sprintf("%s/%s", homeDir, conf.LogConfig.Path)
	}

	/*
		fmt.Printf("Configuration> xml name: %s, version: %s\n", conf.XMLName.Local, conf.Version)
		fmt.Println(conf.LicenseConfig)
		fmt.Println(conf.LogConfig)
		fmt.Println(conf.LogConfig.RotateConfig)
		fmt.Println(conf.CaptureConfig)
	*/

	conf.LogConfig.HomeDir = homeDir

	gSimConfig = &conf

	return &conf, nil
}

func (c SimConfig) GetSimChannels() int {
	return c.Channels
}

func (c SimConfig) GetSimTargetIP() string {
	return c.TargetPhoneConfig.TargetIP
}

func (c SimConfig) ShowConfig() string {
	fmt.Printf("Home Path : %s\n", c.HomeDir)
	fmt.Printf("Caller : %s\n", c.IsCaller)
	fmt.Printf("Channel number : %d\n", c.Channels)
	fmt.Printf("Repeat number : %d\n", c.Repeat)
	fmt.Printf("iComsys SIM Phone Address : %s\n", c.SimPhoneConfig.MYIP)
	fmt.Printf("iComsys Target Phone Address : %s\n", c.GetSimTargetIP())
	fmt.Printf("Log Level : %s\n", c.LogConfig.Level)
	fmt.Printf("Log Path : %s\n", c.LogConfig.Path)
	fmt.Printf("Log Disk Space Limitation : %dMB\n", c.LogConfig.Disklimit)
	fmt.Printf("Log Output : %s\n", c.LogConfig.Output)
	fmt.Printf("Log Rotate : %s\n", c.LogConfig.RotateConfig.YesNo)
	fmt.Printf("Log Rotate File Size : %s\n", c.LogConfig.RotateConfig.Size)
	fmt.Printf("Log Rotate File Number : %s\n", c.LogConfig.RotateConfig.Num)
	fmt.Printf("SIP Port: %d\n", c.SimPhoneConfig.SIPPort)
	fmt.Printf("RTP Port: %d\n", c.SimPhoneConfig.RTPPort)

	confmsg := ""
	confmsg += fmt.Sprintf("Home Path : %s\n", c.HomeDir)
	confmsg += fmt.Sprintf("Caller : %s\n", c.IsCaller)
	confmsg += fmt.Sprintf("Channel number : %d\n", c.Channels)
	confmsg += fmt.Sprintf("iComsys SIM Phone Address : %s\n", c.SimPhoneConfig.MYIP)
	confmsg += fmt.Sprintf("iComsys Target Phone Address : %s\n", c.GetSimTargetIP())
	confmsg += fmt.Sprintf("Log Level : %s\n", c.LogConfig.Level)
	confmsg += fmt.Sprintf("Log Path : %s\n", c.LogConfig.Path)
	confmsg += fmt.Sprintf("Log Disk Space Limitation : %dMB\n", c.LogConfig.Disklimit)
	confmsg += fmt.Sprintf("Log Output : %s\n", c.LogConfig.Output)
	confmsg += fmt.Sprintf("Log Rotate : %s\n\n", c.LogConfig.RotateConfig.YesNo)
	confmsg += fmt.Sprintf("Log Rotate File Size : %s\n", c.LogConfig.RotateConfig.Size)
	confmsg += fmt.Sprintf("Log Rotate File Number : %s\n", c.LogConfig.RotateConfig.Num)
	confmsg += fmt.Sprintf("SIP Port: %d\n", c.SimPhoneConfig.SIPPort)
	confmsg += fmt.Sprintf("RTP Port: %d\n\n", c.SimPhoneConfig.RTPPort)

	return confmsg
}

var gSimConfig *SimConfig

func GetSimConfig() *SimConfig {
	return gSimConfig
}
