package localserver

import (
	context "context"
	"encoding/json"
	"strconv"

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

const (
	INCOMING_PEER_FS                ReqType = "incoming_peer_fs"
	LEAVING_PEER_FS                 ReqType = "leaving_peer_fs"
	WEBRTC_OFFER_FS                 ReqType = "offer_fs"
	WEBRTC_ANSWER_FS                ReqType = "answer_fs"
	WEBRTC_RENNEGOTIATION_OFFER_FS  ReqType = "rennegotiation_offer_fs"
	WEBRTC_RENNEGOTIATION_ANSWER_FS ReqType = "rennegotiation_answer_fs"
	WEBRTC_COUNTER_OFFER_FS         ReqType = "webrtc_counter_offer_fs"
	WEBRTC_CANDIDATE_FS             ReqType = "webrtc_candidate_fs"
)

type WebRTCFsMiddleware struct {
	Manager *WebrtcFsManager
	stream  SignalingService_LinkClient
}

func NewWebRTCFsMiddleware(manager *WebrtcFsManager) (webrtcFsMiddleware *WebRTCFsMiddleware) {
	webrtcFsMiddleware = &WebRTCFsMiddleware{
		Manager: manager,
	}
	return
}

func (wfm *WebRTCFsMiddleware) signalCandidate(to string, candidate *webrtc.ICECandidate) (err error) {
	bs, err := json.Marshal(map[string]string{
		"from":          "lolo_local_serv",
		"to":            to,
		"candidate":     candidate.ToJSON().Candidate,
		"sdpMid":        *candidate.ToJSON().SDPMid,
		"sdpMLineIndex": strconv.Itoa(int(*candidate.ToJSON().SDPMLineIndex)),
	})
	if err != nil {
		return
	}
	err = wfm.stream.Send(&SignalingMessage{
		Type:    string(WEBRTC_CANDIDATE_FS),
		From:    "lolo_local_serv",
		Payload: bs,
	})
	return
}

func (wfm *WebRTCFsMiddleware) Process(ctx context.Context, req *SignalingMessage, stream SignalingService_LinkClient) (err error) {
	done, errCh := make(chan struct{}), make(chan error)
	go func() {
		var payload map[string]string
		if e := json.Unmarshal(req.Payload, &payload); err != nil {
			errCh <- e
			return
		}
		switch req.Type {
		case string(INCOMING_PEER_FS):
			logger.Println("quit squad called")
			if from, ok := payload[FROM]; ok {
				logger.Println(from)
				//wfm.Manager.HandleLeavingMember(from)
				done <- struct{}{}
			}
		case string(PEER_CONNECTION_REQUEST):
			if err := validateRequest(payload, FROM, TO); err != nil {
				errCh <- err
				return
			}
			// if err := wfm.Manager.CreateOffer(ctx, payload[FROM], payload[TO], wfm.signalCandidate); err != nil {
			// 	errCh <- err
			// 	return
			// }
			done <- struct{}{}
		case string(WEBRTC_OFFER_FS):
			if err := validateRequest(payload, FROM, TO, SDP); err != nil {
				errCh <- err
				return
			}
			if err := wfm.Manager.HandleOffer(ctx, payload, wfm.signalCandidate); err != nil {
				errCh <- err
				return
			}
			done <- struct{}{}
		case string(WEBRTC_ANSWER_FS):
			if err := validateRequest(payload, FROM, TO, SDP); err != nil {
				errCh <- err
				return
			}
			if err := wfm.Manager.HandleAnswer(ctx, payload); err != nil {
				errCh <- err
				return
			}
			done <- struct{}{}
		case string(WEBRTC_COUNTER_OFFER_FS):
			if err := validateRequest(payload, FROM); err != nil {
				errCh <- err
				return
			}
			if err := wfm.Manager.HandleCounterOffer(ctx, payload); err != nil {
				errCh <- err
				return
			}
			done <- struct{}{}
		case string(WEBRTC_RENNEGOTIATION_ANSWER_FS):
			if err := validateRequest(payload, FROM, SDP); err != nil {
				errCh <- err
				return
			}
			if err := wfm.Manager.HandleRennegotiationAnswer(payload[FROM], "lolo_local_serv", payload[SDP]); err != nil {
				errCh <- err
				return
			}
			done <- struct{}{}
		case string(WEBRTC_RENNEGOTIATION_OFFER_FS):
			if err := validateRequest(payload, FROM, SDP); err != nil {
				errCh <- err
				return
			}
			if err := wfm.Manager.HandleRennegotiationOffer(payload[FROM], "", payload[SDP]); err != nil {
				errCh <- err
				return
			}
			done <- struct{}{}
		case string(WEBRTC_CANDIDATE_FS):
			if err := validateRequest(payload, FROM, "candidate", "sdpMLineIndex", "sdpMid"); err != nil {
				errCh <- err
				return
			}
			logger.Println(payload)
			i, err := strconv.Atoi(payload["sdpMLineIndex"])
			if err != nil {
				errCh <- err
				return
			}
			SDPMLineIndex := uint16(i)
			sdpMid := payload["sdpMid"]
			logger.Println(sdpMid, SDPMLineIndex)
			if err := wfm.Manager.AddCandidate(&webrtc.ICECandidateInit{
				Candidate:     payload["candidate"],
				SDPMid:        &sdpMid,
				SDPMLineIndex: &SDPMLineIndex,
			}, payload[FROM]); err != nil {
				errCh <- err
				return
			}
			done <- struct{}{}
		default:
			logger.Println("fs is correctly linked")
			done <- struct{}{}
		}
		done <- struct{}{}
	}()
	select {
	case <-ctx.Done():
		err = ctx.Err()
		return
	case <-done:
		return
	case err = <-errCh:
		return
	}
}
