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

package ice

import (
	
	
)

func validateIPString( string) (net.IP, bool, error) {
	 := net.ParseIP()
	if  == nil {
		return nil, false, ErrInvalidNAT1To1IPMapping
	}

	return , (.To4() != nil), nil
}

// ipMapping holds the mapping of local and external IP address
//
//	for a particular IP family.
type ipMapping struct {
	ipSole net.IP            // When non-nil, this is the sole external IP for one local IP assumed
	ipMap  map[string]net.IP // Local-to-external IP mapping (k: local, v: external)
	valid  bool              // If not set any external IP, valid is false
}

func ( *ipMapping) ( net.IP) error {
	if .ipSole != nil || len(.ipMap) > 0 {
		return ErrInvalidNAT1To1IPMapping
	}

	.ipSole = 
	.valid = true

	return nil
}

func ( *ipMapping) (,  net.IP) error {
	if .ipSole != nil {
		return ErrInvalidNAT1To1IPMapping
	}

	 := .String()

	// Check if dup of local IP
	if ,  := .ipMap[];  {
		return ErrInvalidNAT1To1IPMapping
	}

	.ipMap[] = 
	.valid = true

	return nil
}

func ( *ipMapping) ( net.IP) (net.IP, error) {
	if !.valid {
		return , nil
	}

	if .ipSole != nil {
		return .ipSole, nil
	}

	,  := .ipMap[.String()]
	if ! {
		return nil, ErrExternalMappedIPNotFound
	}

	return , nil
}

type externalIPMapper struct {
	ipv4Mapping   ipMapping
	ipv6Mapping   ipMapping
	candidateType CandidateType
}

//nolint:gocognit,cyclop
func newExternalIPMapper(
	 CandidateType,
	 []string,
) (*externalIPMapper, error) {
	if len() == 0 {
		return nil, nil //nolint:nilnil
	}
	if  == CandidateTypeUnspecified {
		 = CandidateTypeHost // Defaults to host
	} else if  != CandidateTypeHost &&  != CandidateTypeServerReflexive {
		return nil, ErrUnsupportedNAT1To1IPCandidateType
	}

	 := &externalIPMapper{
		ipv4Mapping:   ipMapping{ipMap: map[string]net.IP{}},
		ipv6Mapping:   ipMapping{ipMap: map[string]net.IP{}},
		candidateType: ,
	}

	for ,  := range  {
		 := strings.Split(, "/")
		if len() == 0 || len() > 2 {
			return nil, ErrInvalidNAT1To1IPMapping
		}

		, ,  := validateIPString([0])
		if  != nil {
			return nil, 
		}
		if len() == 1 { //nolint:nestif
			if  {
				if  := .ipv4Mapping.setSoleIP();  != nil {
					return nil, 
				}
			} else {
				if  := .ipv6Mapping.setSoleIP();  != nil {
					return nil, 
				}
			}
		} else {
			, ,  := validateIPString([1])
			if  != nil {
				return nil, 
			}
			if  {
				if ! {
					return nil, ErrInvalidNAT1To1IPMapping
				}

				if  := .ipv4Mapping.addIPMapping(, );  != nil {
					return nil, 
				}
			} else {
				if  {
					return nil, ErrInvalidNAT1To1IPMapping
				}

				if  := .ipv6Mapping.addIPMapping(, );  != nil {
					return nil, 
				}
			}
		}
	}

	return , nil
}

func ( *externalIPMapper) ( string) (net.IP, error) {
	, ,  := validateIPString()
	if  != nil {
		return nil, 
	}

	if  {
		return .ipv4Mapping.findExternalIP()
	}

	return .ipv6Mapping.findExternalIP()
}