// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package webrtc

import (
	
	

	
)

type stateChangeOp int

const (
	stateChangeOpSetLocal stateChangeOp = iota + 1
	stateChangeOpSetRemote
)

func ( stateChangeOp) () string {
	switch  {
	case stateChangeOpSetLocal:
		return "SetLocal"
	case stateChangeOpSetRemote:
		return "SetRemote"
	default:
		return "Unknown State Change Operation"
	}
}

// SignalingState indicates the signaling state of the offer/answer process.
type SignalingState int32

const (
	// SignalingStateUnknown is the enum's zero-value.
	SignalingStateUnknown SignalingState = iota

	// SignalingStateStable indicates there is no offer/answer exchange in
	// progress. This is also the initial state, in which case the local and
	// remote descriptions are nil.
	SignalingStateStable

	// SignalingStateHaveLocalOffer indicates that a local description, of
	// type "offer", has been successfully applied.
	SignalingStateHaveLocalOffer

	// SignalingStateHaveRemoteOffer indicates that a remote description, of
	// type "offer", has been successfully applied.
	SignalingStateHaveRemoteOffer

	// SignalingStateHaveLocalPranswer indicates that a remote description
	// of type "offer" has been successfully applied and a local description
	// of type "pranswer" has been successfully applied.
	SignalingStateHaveLocalPranswer

	// SignalingStateHaveRemotePranswer indicates that a local description
	// of type "offer" has been successfully applied and a remote description
	// of type "pranswer" has been successfully applied.
	SignalingStateHaveRemotePranswer

	// SignalingStateClosed indicates The PeerConnection has been closed.
	SignalingStateClosed
)

// This is done this way because of a linter.
const (
	signalingStateStableStr             = "stable"
	signalingStateHaveLocalOfferStr     = "have-local-offer"
	signalingStateHaveRemoteOfferStr    = "have-remote-offer"
	signalingStateHaveLocalPranswerStr  = "have-local-pranswer"
	signalingStateHaveRemotePranswerStr = "have-remote-pranswer"
	signalingStateClosedStr             = "closed"
)

func newSignalingState( string) SignalingState {
	switch  {
	case signalingStateStableStr:
		return SignalingStateStable
	case signalingStateHaveLocalOfferStr:
		return SignalingStateHaveLocalOffer
	case signalingStateHaveRemoteOfferStr:
		return SignalingStateHaveRemoteOffer
	case signalingStateHaveLocalPranswerStr:
		return SignalingStateHaveLocalPranswer
	case signalingStateHaveRemotePranswerStr:
		return SignalingStateHaveRemotePranswer
	case signalingStateClosedStr:
		return SignalingStateClosed
	default:
		return SignalingStateUnknown
	}
}

func ( SignalingState) () string {
	switch  {
	case SignalingStateStable:
		return signalingStateStableStr
	case SignalingStateHaveLocalOffer:
		return signalingStateHaveLocalOfferStr
	case SignalingStateHaveRemoteOffer:
		return signalingStateHaveRemoteOfferStr
	case SignalingStateHaveLocalPranswer:
		return signalingStateHaveLocalPranswerStr
	case SignalingStateHaveRemotePranswer:
		return signalingStateHaveRemotePranswerStr
	case SignalingStateClosed:
		return signalingStateClosedStr
	default:
		return ErrUnknownType.Error()
	}
}

// Get thread safe read value.
func ( *SignalingState) () SignalingState {
	return SignalingState(atomic.LoadInt32((*int32)()))
}

// Set thread safe write value.
func ( *SignalingState) ( SignalingState) {
	atomic.StoreInt32((*int32)(), int32())
}

//nolint:gocognit,cyclop
func checkNextSignalingState(,  SignalingState,  stateChangeOp,  SDPType) (SignalingState, error) {
	// Special case for rollbacks
	if  == SDPTypeRollback &&  == SignalingStateStable {
		return , &rtcerr.InvalidModificationError{
			Err: errSignalingStateCannotRollback,
		}
	}

	// 4.3.1 valid state transitions
	switch  { // nolint:exhaustive
	case SignalingStateStable:
		switch  {
		case stateChangeOpSetLocal:
			// stable->SetLocal(offer)->have-local-offer
			if  == SDPTypeOffer &&  == SignalingStateHaveLocalOffer {
				return , nil
			}
		case stateChangeOpSetRemote:
			// stable->SetRemote(offer)->have-remote-offer
			if  == SDPTypeOffer &&  == SignalingStateHaveRemoteOffer {
				return , nil
			}
		}
	case SignalingStateHaveLocalOffer:
		if  == stateChangeOpSetRemote {
			switch  { // nolint:exhaustive
			// have-local-offer->SetRemote(answer)->stable
			case SDPTypeAnswer:
				if  == SignalingStateStable {
					return , nil
				}
			// have-local-offer->SetRemote(pranswer)->have-remote-pranswer
			case SDPTypePranswer:
				if  == SignalingStateHaveRemotePranswer {
					return , nil
				}
			}
		}
	case SignalingStateHaveRemotePranswer:
		if  == stateChangeOpSetRemote &&  == SDPTypeAnswer {
			// have-remote-pranswer->SetRemote(answer)->stable
			if  == SignalingStateStable {
				return , nil
			}
		}
	case SignalingStateHaveRemoteOffer:
		if  == stateChangeOpSetLocal {
			switch  { // nolint:exhaustive
			// have-remote-offer->SetLocal(answer)->stable
			case SDPTypeAnswer:
				if  == SignalingStateStable {
					return , nil
				}
			// have-remote-offer->SetLocal(pranswer)->have-local-pranswer
			case SDPTypePranswer:
				if  == SignalingStateHaveLocalPranswer {
					return , nil
				}
			}
		}
	case SignalingStateHaveLocalPranswer:
		if  == stateChangeOpSetLocal &&  == SDPTypeAnswer {
			// have-local-pranswer->SetLocal(answer)->stable
			if  == SignalingStateStable {
				return , nil
			}
		}
	}

	return , &rtcerr.InvalidModificationError{
		Err: fmt.Errorf("%w: %s->%s(%s)->%s", errSignalingStateProposedTransitionInvalid, , , , ),
	}
}