package ami

import (
	"crm-api/api/admin/vtiger"
	"crm-api/api/admin/zoho"
	"crm-api/internal/app/ami/model"
	"crm-api/pkg/configs"
	"crm-api/pkg/lfshook"
	"strings"

	"crm-api/internal/app/redis"
	socketio "crm-api/internal/app/socket_io"

	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
	"github.com/tqcenglish/amigo-go"
	"github.com/tqcenglish/amigo-go/pkg"
)

var AminInstance *amigo.Amigo

// const VTIGER_URL = "https://zycoo1.od2.vtiger.com"

// 认证信息添加到 ./config.yaml
// const BasicAuthUser = "juncheng.du@zycoo.com"
// const BasicAuthPWD = "8DJ3O28MCZ4sPAk5"
// const ApiKey = "X-VTIGER-SECRET"
// const ApiKeyValue = "174781790673da476e25cf"

func StartAMI(connectOKCallBack func(), handleEvents []func(event map[string]string), apiType string) {
	lfshook.NewLogger().Info("Start AMI")
	settings := &amigo.Settings{
		Host:     configs.ConfigGlobal.AsteriskAMIHost,
		Port:     configs.ConfigGlobal.AsteriskAMIPort,
		Username: configs.ConfigGlobal.AsteriskAMIUser,
		Password: configs.ConfigGlobal.AsteriskAMISecret,
		LogLevel: logrus.InfoLevel}
	lfshook.NewLogger().Infof("ami setting: %+v", settings)
	AminInstance = amigo.New(settings, lfshook.NewLogger())
	AminInstance.EventOn(func(payload ...interface{}) {
		// lfshook.NewLogger().Infof("ami event on %+v", payload[0])
		event := payload[0].(map[string]string)

		handleAMIBridge(event)
		handleAMI(event)
		handleSocketIO(event)

		// /* 20241128 vtiger crm 对应 ============================================================
		if apiType == "CRM_vtiger" {
			// phoneCalls(event)
			vtiger.PhoneCalls(event)
		} else if apiType == "CRM_zoho" {
			// callNotify(event)
			// zoho.RefreshToken()
			zoho.CallClicktodialerror(event) // 将函数名称 callNotify 改为 CallNotify 即可

		}
		// * ===================================================================================== */
		/* 20241128 vtiger crm 对应 ============================================================
		fmt.Println("=========================================== ")
		fmt.Println("event[] = ", event)
		fmt.Println("event = ", event["Event"])
		fmt.Println("AMIPushUrl = ", configs.PushConfigValue.AMIPushUrl)
		fmt.Println("Channel = ", event["Channel"])

		var callId string
		if event["Channel"] != "" {
			callId = strings.Split(strings.Split(event["Channel"], "/")[1], "-")[0]
			fmt.Println("callId = ", callId)
		}

		// if configs.PushConfigValue.AMIPushUrl != "" {
		// 	for _, eventName := range configs.PushConfigValue.AMIEvents {
		// 		if eventName == event["Event"] {
		// 			go httpclient.Post(event, configs.PushConfigValue.AMIPushUrl)
		// 			break
		// 		}
		// 	}
		// }
		callId = "10000007"                                                                                           // 测试用，每次测试 +1
		recordingUrl := "https%3A%2F%2Fs3.amazonaws.com%2Frecordings_2013%2F8e522852-72aa-11e5-ab5f-842b2b021118.mp3" // 测试用
		event["Exten"] = "123456789"                                                                                  // 测试用
		fmt.Println("Exten = ", event["Exten"])

		// 读取vtiger配置文件
		confPath := "/etc/asterisk/vtiger_api.conf"
		cfg, err := ini.Load(confPath)
		if err != nil {
			lfshook.NewLogger().Error(err)
			return
		}
		VTIGER_URL := cfg.Section("general").Key("vtigerUrl").String()
		if VTIGER_URL == "" {
			lfshook.NewLogger().Error("/etc/asterisk/vtiger_api.conf not set vtigerUrl")
			return
		}

		// 呼叫发起事件
		if event["Event"] == "DialBegin" { // "DialBegin" "Newchannel"
			// https://zycoo1.od2.vtiger.com/modules/PhoneCalls/callbacks/Generic.php?from=147258369&to=12300001&event=call_initiated&call_id=12345678&direction=inbound
			// https://zycoo1.od2.vtiger.com/modules/PhoneCalls/callbacks/Generic.php?from=86147258369&event=call_initiated&call_id=12345678  // 可以省去部分参数
			getURL := fmt.Sprintf("%s/modules/PhoneCalls/callbacks/Generic.php?from=%s&event=call_initiated&call_id=%s", VTIGER_URL, event["Exten"], callId)
			// fmt.Println("getURL = ", getURL)
			// go httpclient.Get(getURL)
			go httpclient.ApiKeyGet(getURL) // 后面要不要把用户密码给传过去

			// resp := httpclient.ApiKeyGet(getURL)
			// // 读取请求后的响应
			// data, err := ioutil.ReadAll(resp.Body)
			// if err != nil {
			// 	fmt.Println("读取请求后的响应时发生错误:", err)
			// 	return
			// }
			// // 打印请求后的响应
			// fmt.Printf("data = %+v\n", string(data))

			// 呼叫已连接事件
		} else if event["Event"] == "BridgeEnter" { // "Newstate" "BridgeEnter"
			// https://zycoo1.od2.vtiger.com/modules/PhoneCalls/callbacks/Generic.php?from=86147258369&to=12300001&event=call_connected&call_id=12345678
			// https://zycoo1.od2.vtiger.com/modules/PhoneCalls/callbacks/Generic.php?event=call_connected&call_id=12345678  // 可以省去部分参数
			getURL := fmt.Sprintf("%s/modules/PhoneCalls/callbacks/Generic.php?event=call_connected&call_id=%s", VTIGER_URL, callId)
			// fmt.Println("getURL = ", getURL)
			go httpclient.ApiKeyGet(getURL)

			// 通话录音事件
		} else if event["Event"] == "Cdr" {
			// https://zycoo1.od2.vtiger.com/modules/PhoneCalls/callbacks/Generic.php?call_id=12345678&event=call_recording&recordingurl=https%3A%2F%2Fs3.amazonaws.com%2Frecordings_2013%2F8e522852-72aa-11e5-ab5f-842b2b021118.mp3
			getURL := fmt.Sprintf("%s/modules/PhoneCalls/callbacks/Generic.php?call_id=%s&event=call_recording&recordingurl=%s", VTIGER_URL, callId, recordingUrl)
			// fmt.Println("getURL = ", getURL)
			go httpclient.ApiKeyGet(getURL)

			// 呼叫转移事件
			// Command:SET VARIABLE FORWARD_TYPE "busy"   Command:SET VARIABLE FORWARD_DEST "136"
			// Command:SET VARIABLE FORWARD_TYPE "always"  Command:SET VARIABLE FORWARD_DEST "136"
			// Command:SET VARIABLE FORWARD_TYPE "noan_busy"  Command:SET VARIABLE FORWARD_DEST "136"
			// Command:SET VARIABLE FORWARD_TYPE "noan_unav"   Command:SET VARIABLE FORWARD_DEST "136"
			// Command:SET VARIABLE FORWARD_TYPE "unavailable"  Command:SET VARIABLE FORWARD_DEST "136"
		} else if strings.Contains(event["Command"], "FORWARD_DEST") {
			// transferredNumber := strings.Split(event["Command"], "\"")[1] // 正式用
			transferredNumber := "147258369" // 测试用
			// fmt.Println("Command = ", event["Command"])
			// fmt.Println("transferredNumber = ", transferredNumber)

			// https://zycoo1.od2.vtiger.com/modules/PhoneCalls/callbacks/Generic.php?call_id=12345678&event=call_transfer&transferred_number=147258369
			getURL := fmt.Sprintf("%s/modules/PhoneCalls/callbacks/Generic.php?call_id=%s&event=call_transfer&transferred_number=%s", VTIGER_URL, callId, transferredNumber)
			// fmt.Println("getURL = ", getURL)
			go httpclient.ApiKeyGet(getURL)

			// 呼叫挂断事件
		} else if event["Event"] == "HangupRequest" { // "HangupRequest" "Hangup"
			// https://zycoo1.od2.vtiger.com/modules/PhoneCalls/callbacks/Generic.php?call_id=12345678&event=call_hangup
			getURL := fmt.Sprintf("%s/modules/PhoneCalls/callbacks/Generic.php?call_id=%s&event=call_hangup", VTIGER_URL, callId)
			fmt.Println("getURL = ", getURL)
			go httpclient.ApiKeyGet(getURL)
		}
		// 按编号搜索API 暂时用的以下接口
		// group.GET("/vtiger/lookup", contactsInfo) // 按编号搜索

		// * ===================================================================================== */

		for _, handle := range handleEvents {
			go handle(event)
		}

	})
	AminInstance.ConnectOn(func(payload ...interface{}) {
		if payload[0] == pkg.Connect_OK {
			lfshook.NewLogger().Info("ami connect ok")
			ClearBridge()
			connectOKCallBack()
		} else {
			lfshook.NewLogger().Errorf("ami connect failure %+v", payload)
		}
	})
	AminInstance.Connect()
}

func handleAMI(event map[string]string) {
	switch event["Event"] {
	case "ContactStatus":
		endpointName := event["EndpointName"]
		contactStatus := event["ContactStatus"]

		// NonQualified
		round := event["RoundtripUsec"]
		if round == "" {
			round = "1000"
		}
		uri := event["URI"]
		data := strings.Split(uri, "@")
		if len(data) < 2 {
			lfshook.NewLogger().Debugf("split URI by @ error URI: %s event:%+v", uri, event)
			return
		}
		first := data[1]

		// 中继变化也会触发此事件, 需要忽略
		switch contactStatus {
		case "Removed":
			//remove contact
			redis.ExtensionDel(endpointName, event["URI"], strings.Split(first, ":")[0], round)
		case "Reachable":
			fallthrough
		default:
			redis.ExtensionSet(endpointName, event["URI"], strings.Split(first, ":")[0], round)
		}
	case "ExtensionStatus":
		status := &model.ExtensionStatus{
			Event:      event["Event"],
			Exten:      event["Exten"],
			Context:    event["Context"],
			Hint:       event["Hint"],
			Status:     event["Status"],
			StatusText: event["StatusText"],
		}
		redis.ExtensionSetStatus(status)
	}
}

func handleSocketIO(event map[string]string) {
	var data interface{}
	switch event["Event"] {
	case "ExtensionStatus":
		lfshook.NewLogger().Tracef("ExtensionStatus %+v", event)
		status := &model.ExtensionStatus{}
		mapstructure.Decode(event, status)
		data = status
	case "QueueMemberStatus":
		lfshook.NewLogger().Tracef("QueueMemberStatus %+v", event)
		status := &model.QueueMember{}
		mapstructure.Decode(event, status)
		data = status
	case "QueueCallerJoin":
		status := &model.QueueCallerJoin{}
		lfshook.NewLogger().Infof("status %+v", event)
		mapstructure.Decode(event, status)
		data = status
	case "QueueCallerLeave":
		status := &model.QueueCallerLeave{}
		mapstructure.Decode(event, status)
		data = status
	case "QueueCallerAbandon":
		status := &model.QueueCallerAbandon{}
		mapstructure.Decode(event, status)
		data = status
	case "ParkedCall":
		status := &model.ParkedCall{}
		mapstructure.Decode(event, status)
		data = status
	case "ParkedCallTimeOut":
		status := &model.ParkedCallTimeOut{}
		mapstructure.Decode(event, status)
		data = status
	case "ParkedCallGiveUp":
		status := &model.ParkedCallGiveUp{}
		mapstructure.Decode(event, status)
		data = status
	case "UnParkedCall":
		status := &model.UnParkedCall{}
		mapstructure.Decode(event, status)
		data = status

	case "MeetmeEnd":
		status := &model.MeetmeEnd{}
		mapstructure.Decode(event, status)
		data = status

	case "MeetmeJoin":
		fallthrough
	case "MeetmeLeave":
		fallthrough
	case "MeetmeMute":
		fallthrough
	case "MeetmeTalking":
		fallthrough
	case "MeetmeTalkRequest":
		status := &model.Meetme{}
		mapstructure.Decode(event, status)
		data = status

	case "PresenceStateChange":
		status := &model.PresenceStateChange{}
		mapstructure.Decode(event, status)
		if status.Presentity != "" {
			data := strings.Split(status.Presentity, ":")
			if len(data) == 2 {
				status.Extension = data[1]
			}
		}

		if status.Status == "dnd" {
			status.DndStatus = "yes"
		} else {
			status.DndStatus = ""
		}
		data = status

	case "DialBegin":
		fallthrough
	case "DialEnd":
		fallthrough
	case "DialState":
		status := &model.Dial{}
		mapstructure.Decode(event, status)
		data = status

	case "Newstate":
		status := &model.Newstate{}
		mapstructure.Decode(event, status)
		data = status

	case "Hangup":
		status := &model.Hangup{}
		mapstructure.Decode(event, status)
		data = status

	case "UserEvent":
		switch event["UserEvent"] {
		case "SetDND":
			status := &model.SetDND{}
			mapstructure.Decode(event, status)
			data = status
			if status.DNDStatus == "1" {
				redis.ExtensionDNDSet(status.Exten, "yes")
			} else {
				redis.ExtensionDNDDel(status.Exten)
			}
			event["Event"] = event["UserEvent"]
		case "WakeUpStatus":
			status := &model.WakeUpStatus{}
			mapstructure.Decode(event, status)
			data = status
			event["Event"] = event["UserEvent"]
		default:
			data = event
		}
	case "SuccessfulAuth":
		// 获取上线 IP 地址
		// !TODO 通过代理服务器地址不正确
		status := &model.SuccessfulAuth{}
		mapstructure.Decode(event, status)
		status.GetAddress()
		data = status

	case "ContactStatus":
		status := &model.ContactStatus{}
		mapstructure.Decode(event, status)
		status.GetAddress()
		data = status

	case "MessageWaiting":
		status := &model.MessageWaiting{}
		mapstructure.Decode(event, status)
		status.GetExtension()
		data = status
		if status.Extension == "" {
			lfshook.NewLogger().Warnf("MessageWaiting error %+v", event)
			return
		}
	default:
		// if !strings.Contains(event["Event"], "RTP") &&
		// 	!strings.Contains(event["Event"], "RTCP") &&
		// 	!strings.Contains(event["Event"], "VarSet") &&
		// 	!strings.Contains(event["Event"], "Bridge") &&
		// 	!strings.Contains(event["Event"], "New") &&
		// 	!strings.Contains(event["Event"], "SuccessfulAuth") &&
		// 	!strings.Contains(event["Event"], "ChallengeSent") {
		// 	lfshook.NewLogger().Info(event)
		// }
	}

	if data != nil {
		// if configs.ConfigGlobal.FilterEventPushUrl != "" {
		// 	httpclient.Post(data, configs.ConfigGlobal.FilterEventPushUrl)
		// }
		socketio.SocketIOServer.BroadcastToNamespace("", event["Event"], data)
	}
}

func Connected() bool {
	if AminInstance != nil {
		return AminInstance.Connected()
	}
	return false
}
