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

//go:build !js
// +build !js

package webrtc

import (
	

	
	
)

// ICEServer describes a single STUN and TURN server that can be used by
// the ICEAgent to establish a connection with a peer.
type ICEServer struct {
	URLs           []string          `json:"urls"`
	Username       string            `json:"username,omitempty"`
	Credential     interface{}       `json:"credential,omitempty"`
	CredentialType ICECredentialType `json:"credentialType,omitempty"`
}

func ( ICEServer) ( int) (*stun.URI, error) {
	return stun.ParseURI(.URLs[])
}

func ( ICEServer) () error {
	,  := .urls()

	return 
}

func ( ICEServer) () ([]*stun.URI, error) { //nolint:cyclop
	 := []*stun.URI{}

	for  := range .URLs {
		,  := .parseURL()
		if  != nil {
			return nil, &rtcerr.InvalidAccessError{Err: }
		}

		if .Scheme == stun.SchemeTypeTURN || .Scheme == stun.SchemeTypeTURNS {
			// https://www.w3.org/TR/webrtc/#set-the-configuration (step #11.3.2)
			if .Username == "" || .Credential == nil {
				return nil, &rtcerr.InvalidAccessError{Err: ErrNoTurnCredentials}
			}
			.Username = .Username

			switch .CredentialType {
			case ICECredentialTypePassword:
				// https://www.w3.org/TR/webrtc/#set-the-configuration (step #11.3.3)
				,  := .Credential.(string)
				if ! {
					return nil, &rtcerr.InvalidAccessError{Err: ErrTurnCredentials}
				}
				.Password = 

			case ICECredentialTypeOauth:
				// https://www.w3.org/TR/webrtc/#set-the-configuration (step #11.3.4)
				if ,  := .Credential.(OAuthCredential); ! {
					return nil, &rtcerr.InvalidAccessError{Err: ErrTurnCredentials}
				}

			default:
				return nil, &rtcerr.InvalidAccessError{Err: ErrTurnCredentials}
			}
		}

		 = append(, )
	}

	return , nil
}

func iceserverUnmarshalUrls( interface{}) (*[]string, error) {
	,  := .([]interface{})
	if ! {
		return nil, errInvalidICEServer
	}
	 := make([]string, len())
	for ,  := range  {
		[],  = .(string)
		if ! {
			return nil, errInvalidICEServer
		}
	}

	return &, nil
}

func iceserverUnmarshalOauth( interface{}) (*OAuthCredential, error) {
	,  := .(map[string]interface{})
	if ! {
		return nil, errInvalidICEServer
	}
	,  := ["MACKey"].(string)
	if ! {
		return nil, errInvalidICEServer
	}
	,  := ["AccessToken"].(string)
	if ! {
		return nil, errInvalidICEServer
	}

	return &OAuthCredential{
		MACKey:      ,
		AccessToken: ,
	}, nil
}

func ( *ICEServer) ( map[string]interface{}) error { //nolint:cyclop
	if ,  := ["urls"];  {
		,  := iceserverUnmarshalUrls()
		if  != nil {
			return 
		}
		.URLs = *
	} else {
		.URLs = []string{}
	}

	if ,  := ["username"];  {
		.Username,  = .(string)
		if ! {
			return errInvalidICEServer
		}
	}
	if ,  := ["credentialType"];  {
		,  := .(string)
		if ! {
			return errInvalidICEServer
		}
		,  := newICECredentialType()
		if  != nil {
			return 
		}
		.CredentialType = 
	} else {
		.CredentialType = ICECredentialTypePassword
	}
	if ,  := ["credential"];  {
		switch .CredentialType {
		case ICECredentialTypePassword:
			.Credential = 
		case ICECredentialTypeOauth:
			,  := iceserverUnmarshalOauth()
			if  != nil {
				return 
			}
			.Credential = *
		default:
			return errInvalidICECredentialTypeString
		}
	}

	return nil
}

// UnmarshalJSON parses the JSON-encoded data and stores the result.
func ( *ICEServer) ( []byte) error {
	var  interface{}
	 := json.Unmarshal(, &)
	if  != nil {
		return 
	}
	if ,  := .(map[string]interface{});  {
		return .iceserverUnmarshalFields()
	}

	return errInvalidICEServer
}

// MarshalJSON returns the JSON encoding.
func ( ICEServer) () ([]byte, error) {
	 := make(map[string]interface{})
	["urls"] = .URLs
	if .Username != "" {
		["username"] = .Username
	}
	if .Credential != nil {
		["credential"] = .Credential
	}
	["credentialType"] = .CredentialType

	return json.Marshal()
}