package ami

import (
	socketio "crm-api/internal/app/socket_io"
	"crm-api/pkg/lfshook"
	"fmt"
	"sync"

	"github.com/mitchellh/mapstructure"
)

var bridgeMap sync.Map

const bridgeEventName = "CustomBridgeEvent"

type BridgeEvent struct {
	Event string `json:"event"`
	// Timestamp         string `json:"timestamp"`
	BridgeUniqueid          string `json:"-"`
	Channel                 string `json:"channel"`
	ChannelState            string `json:"channelState"`
	ChannelStateDesc        string `json:"channelStateDesc"`
	CallerIDNum             string `json:"callerIDNumber"`
	CallerIDName            string `json:"callerIDName"`
	CallerConnectedLineNum  string `json:"callerConnectedLineNumber"`
	CallerConnectedLineName string `json:"callerConnectedLineName"`
	BridgeType              string `json:"bridgeType"`
	BridgeNumChannels       string `json:"bridgeNumberChannels"`
	Uniqueid                string `json:"uniqueid"`
}

func (event BridgeEvent) String() string {
	return fmt.Sprintf("channel: %s, uniqueid: %s\n", event.Channel, event.Uniqueid)
}

func handleAMIBridge(event map[string]string) {
	if event["BridgeType"] != "basic" {
		return
	}

	if event["CallerIDName"] == "conference" {
		return
	}

	switch event["Event"] {
	case "BridgeCreate":
		bridgeMap.Store(event["BridgeUniqueid"], []*BridgeEvent{})
	case "BridgeEnter":
		status := &BridgeEvent{}
		mapstructure.Decode(event, status)
		if events, ok := bridgeMap.Load(status.BridgeUniqueid); ok {
			bridgeMap.Store(status.BridgeUniqueid, append(events.([]*BridgeEvent), status))
		} else {
			lfshook.NewLogger().Warnf("BridgeEnter add failure id: %s on load", status.BridgeUniqueid)
		}
		socketio.SocketIOServer.BroadcastToNamespace("", bridgeEventName, GetBridgeMapValue())
	case "BridgeLeave":
		status := &BridgeEvent{}
		mapstructure.Decode(event, status)
		if events, ok := bridgeMap.Load(status.BridgeUniqueid); ok {
			events := events.([]*BridgeEvent)
			for index, event := range events {
				if event.Channel == status.Channel {
					if index == len(events)-1 {
						bridgeMap.Store(status.BridgeUniqueid, events[:index])
					} else {
						bridgeMap.Store(status.BridgeUniqueid, append(events[:index], events[index+1]))
					}
					break
				}
			}
		} else {
			lfshook.NewLogger().Warnf("BridgeLeave remove failure id: %s on load", status.BridgeUniqueid)
		}
		socketio.SocketIOServer.BroadcastToNamespace("", bridgeEventName, GetBridgeMapValue())
	case "BridgeDestroy":
		bridgeMap.Delete(event["BridgeUniqueid"])
		socketio.SocketIOServer.BroadcastToNamespace("", bridgeEventName, GetBridgeMapValue())
	}

}

func GetBridgeMapValue() (result map[string][]*BridgeEvent) {
	result = make(map[string][]*BridgeEvent)
	bridgeMap.Range(func(key, value interface{}) bool {
		events := value.([]*BridgeEvent)
		result[key.(string)] = events
		return true
	})
	return
}

// ClearBridge Asterisk 重启，内部通话清空， AMI 重连成功也需求清空 Bridge
func ClearBridge() {
	bridgeMap.Range(func(key, value interface{}) bool {
		bridgeMap.Delete(key)
		return true
	})
}
