package binary

import (
	
	
	

	
	
)

const (
	// subsectionIDModuleName contains only the module name.
	subsectionIDModuleName = uint8(0)
	// subsectionIDFunctionNames is a map of indices to function names, in ascending order by function index
	subsectionIDFunctionNames = uint8(1)
	// subsectionIDLocalNames contain a map of function indices to a map of local indices to their names, in ascending
	// order by function and local index
	subsectionIDLocalNames = uint8(2)
)

// decodeNameSection deserializes the data associated with the "name" key in SectionIDCustom according to the
// standard:
//
// * ModuleName decode from subsection 0
// * FunctionNames decode from subsection 1
// * LocalNames decode from subsection 2
//
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namesec
func decodeNameSection( *bytes.Reader,  uint64) ( *wasm.NameSection,  error) {
	// TODO: add leb128 functions that work on []byte and offset. While using a reader allows us to reuse reader-based
	// leb128 functions, it is less efficient, causes untestable code and in some cases more complex vs plain []byte.
	 = &wasm.NameSection{}

	// subsectionID is decoded if known, and skipped if not
	var  uint8
	// subsectionSize is the length to skip when the subsectionID is unknown
	var  uint32
	var  uint64
	for  > 0 {
		if ,  = .ReadByte();  != nil {
			if  == io.EOF {
				return , nil
			}
			// TODO: untestable as this can't fail for a reason beside EOF reading a byte from a buffer
			return nil, fmt.Errorf("failed to read a subsection ID: %w", )
		}
		--

		if , ,  = leb128.DecodeUint32();  != nil {
			return nil, fmt.Errorf("failed to read the size of subsection[%d]: %w", , )
		}
		 -= 

		switch  {
		case subsectionIDModuleName:
			if .ModuleName, _,  = decodeUTF8(, "module name");  != nil {
				return nil, 
			}
		case subsectionIDFunctionNames:
			if .FunctionNames,  = decodeFunctionNames();  != nil {
				return nil, 
			}
		case subsectionIDLocalNames:
			if .LocalNames,  = decodeLocalNames();  != nil {
				return nil, 
			}
		default: // Skip other subsections.
			// Note: Not Seek because it doesn't err when given an offset past EOF. Rather, it leads to undefined state.
			if _,  = io.CopyN(io.Discard, , int64());  != nil {
				return nil, fmt.Errorf("failed to skip subsection[%d]: %w", , )
			}
		}
		 -= uint64()
	}
	return
}

func decodeFunctionNames( *bytes.Reader) (wasm.NameMap, error) {
	,  := decodeFunctionCount(, subsectionIDFunctionNames)
	if  != nil {
		return nil, 
	}

	 := make(wasm.NameMap, )
	for  := uint32(0);  < ; ++ {
		,  := decodeFunctionIndex(, subsectionIDFunctionNames)
		if  != nil {
			return nil, 
		}

		, ,  := decodeUTF8(, "function[%d] name", )
		if  != nil {
			return nil, 
		}
		[] = wasm.NameAssoc{Index: , Name: }
	}
	return , nil
}

func decodeLocalNames( *bytes.Reader) (wasm.IndirectNameMap, error) {
	,  := decodeFunctionCount(, subsectionIDLocalNames)
	if  != nil {
		return nil, 
	}

	 := make(wasm.IndirectNameMap, )
	for  := uint32(0);  < ; ++ {
		,  := decodeFunctionIndex(, subsectionIDLocalNames)
		if  != nil {
			return nil, 
		}

		, ,  := leb128.DecodeUint32()
		if  != nil {
			return nil, fmt.Errorf("failed to read the local count for function[%d]: %w", , )
		}

		 := make(wasm.NameMap, )
		for  := uint32(0);  < ; ++ {
			, ,  := leb128.DecodeUint32()
			if  != nil {
				return nil, fmt.Errorf("failed to read a local index of function[%d]: %w", , )
			}

			, ,  := decodeUTF8(, "function[%d] local[%d] name", , )
			if  != nil {
				return nil, 
			}
			[] = wasm.NameAssoc{Index: , Name: }
		}
		[] = wasm.NameMapAssoc{Index: , NameMap: }
	}
	return , nil
}

func decodeFunctionIndex( *bytes.Reader,  uint8) (uint32, error) {
	, ,  := leb128.DecodeUint32()
	if  != nil {
		return 0, fmt.Errorf("failed to read a function index in subsection[%d]: %w", , )
	}
	return , nil
}

func decodeFunctionCount( *bytes.Reader,  uint8) (uint32, error) {
	, ,  := leb128.DecodeUint32()
	if  != nil {
		return 0, fmt.Errorf("failed to read the function count of subsection[%d]: %w", , )
	}
	return , nil
}