package localserver

import (
	"fmt"
	"sync"
	"sync/atomic"

	"github.com/pion/webrtc/v3"
)

const (
	NAME      = "name"
	ID        = "ID"
	SDP       = "sdp"
	CANDIDATE = "webrtc_candidate"
	SQUAD_ID  = "squadId"
	FROM      = "from"
	TO        = "to"

	STOP_CALL                  = "stop_call"
	LIST_HOSTED_SQUADS_BY_HOST = "list_hosted_squads_by_host"
	LEAVE_SQUAD

	bufferedAmountLowThreshold uint64 = 512 * 1024
)

type OnICECandidateFunc func(string, *webrtc.ICECandidate) error

type RTCPeerConnection struct {
	*webrtc.PeerConnection
	id              string
	makingOffer     bool
	negotiate       func(string, string)
	makingOfferLock *sync.Mutex
}

type DataChannel struct {
	DataChannel                       *webrtc.DataChannel
	bufferedAmountLowThresholdReached <-chan struct{}
	l                                 *uint32
}

type PeerSender struct {
	ID          string
	Transceiver *webrtc.RTPTransceiver
	Sender      *webrtc.RTPSender
}

type CallEvent struct {
	EventId string                 `json:"eventId"`
	From    string                 `json:"from"`
	Data    []byte                 `json:"data"`
	Payload map[string]interface{} `json:"payload"`
}

type RemoteTrack struct {
	ID    string
	Track *webrtc.TrackLocalStaticRTP
	rdv   *int32
}

func validateRequest(req map[string]string, entries ...string) (err error) {
	for _, entry := range entries {
		if _, ok := req[entry]; !ok {
			err = fmt.Errorf("no field %s in req payload", entry)
			return
		}
	}
	return
}

func ToStringSlice(slice []any) (strSlice []string, err error) {
	strSlice = []string{}
	for _, value := range slice {
		if strValue, ok := value.(string); ok {
			strSlice = append(strSlice, strValue)
		} else {
			err = fmt.Errorf("value in slice of wrong type")
			return
		}
	}
	return
}

func atomicallyExecute(flag *uint32, job func() (err error)) (err error) {
	for {
		if atomic.CompareAndSwapUint32(flag, 0, 1) {
			defer atomic.SwapUint32(flag, 0)
			err = job()
			break
		}
	}
	return
}

func VerifyFieldsString(payload map[string]any, fields ...string) (err error) {
	for _, field := range fields {
		if _, ok := payload[field]; !ok {
			err = fmt.Errorf("no field %s in payload", field)
			return
		} else if _, ok := payload[field].(string); !ok {
			err = fmt.Errorf("field %s in payload is not a string", field)
			return
		}
	}
	return
}

func VerifyFieldsBool(payload map[string]any, fields ...string) (err error) {
	for _, field := range fields {
		if _, ok := payload[field]; !ok {
			err = fmt.Errorf("no field %s in payload", field)
			return
		} else if _, ok := payload[field].(bool); !ok {
			err = fmt.Errorf("field %s in payload is not a bool", field)
			return
		}
	}
	return
}

func VerifyFieldsFloat64(payload map[string]any, fields ...string) (err error) {
	for _, field := range fields {
		if _, ok := payload[field]; !ok {
			err = fmt.Errorf("no field %s in payload", field)
			return
		} else if _, ok := payload[field].(float64); !ok {
			err = fmt.Errorf("field %s in payload is not a float64", field)
			return
		}
	}
	return
}

func VerifyFieldsSliceInterface(payload map[string]any, fields ...string) (err error) {
	for _, field := range fields {
		if _, ok := payload[field]; !ok {
			err = fmt.Errorf("no field %s in payload", field)
			return
		} else if _, ok := payload[field].([]any); !ok {
			err = fmt.Errorf("field %s in payload is not a []any", field)
			return
		}
	}
	return
}
