package sys

import (
	
	
	
	
	

	experimentalsys 
	
	
)

// Context holds module-scoped system resources currently only supported by
// built-in host functions.
type Context struct {
	args, environ         [][]byte
	argsSize, environSize uint32

	walltime           sys.Walltime
	walltimeResolution sys.ClockResolution
	nanotime           sys.Nanotime
	nanotimeResolution sys.ClockResolution
	nanosleep          sys.Nanosleep
	osyield            sys.Osyield
	randSource         io.Reader
	fsc                FSContext
}

// Args is like os.Args and defaults to nil.
//
// Note: The count will never be more than math.MaxUint32.
// See wazero.ModuleConfig WithArgs
func ( *Context) () [][]byte {
	return .args
}

// ArgsSize is the size to encode Args as Null-terminated strings.
//
// Note: To get the size without null-terminators, subtract the length of Args from this value.
// See wazero.ModuleConfig WithArgs
// See https://en.wikipedia.org/wiki/Null-terminated_string
func ( *Context) () uint32 {
	return .argsSize
}

// Environ are "key=value" entries like os.Environ and default to nil.
//
// Note: The count will never be more than math.MaxUint32.
// See wazero.ModuleConfig WithEnv
func ( *Context) () [][]byte {
	return .environ
}

// EnvironSize is the size to encode Environ as Null-terminated strings.
//
// Note: To get the size without null-terminators, subtract the length of Environ from this value.
// See wazero.ModuleConfig WithEnv
// See https://en.wikipedia.org/wiki/Null-terminated_string
func ( *Context) () uint32 {
	return .environSize
}

// Walltime implements platform.Walltime.
func ( *Context) () ( int64,  int32) {
	return .walltime()
}

// WalltimeNanos returns platform.Walltime as epoch nanoseconds.
func ( *Context) () int64 {
	,  := .Walltime()
	return ( * time.Second.Nanoseconds()) + int64()
}

// WalltimeResolution returns resolution of Walltime.
func ( *Context) () sys.ClockResolution {
	return .walltimeResolution
}

// Nanotime implements sys.Nanotime.
func ( *Context) () int64 {
	return .nanotime()
}

// NanotimeResolution returns resolution of Nanotime.
func ( *Context) () sys.ClockResolution {
	return .nanotimeResolution
}

// Nanosleep implements sys.Nanosleep.
func ( *Context) ( int64) {
	.nanosleep()
}

// Osyield implements sys.Osyield.
func ( *Context) () {
	.osyield()
}

// FS returns the possibly empty (UnimplementedFS) file system context.
func ( *Context) () *FSContext {
	return &.fsc
}

// RandSource is a source of random bytes and defaults to a deterministic source.
// see wazero.ModuleConfig WithRandSource
func ( *Context) () io.Reader {
	return .randSource
}

// DefaultContext returns Context with no values set except a possible nil
// sys.FS.
//
// Note: This is only used for testing.
func ( experimentalsys.FS) *Context {
	if ,  := NewContext(0, nil, nil, nil, nil, nil, nil, nil, 0, nil, 0, nil, nil, []experimentalsys.FS{}, []string{""}, nil);  != nil {
		panic(fmt.Errorf("BUG: DefaultContext should never error: %w", ))
	} else {
		return 
	}
}

// NewContext is a factory function which helps avoid needing to know defaults or exporting all fields.
// Note: max is exposed for testing. max is only used for env/args validation.
func (
	 uint32,
	,  [][]byte,
	 io.Reader,
	,  io.Writer,
	 io.Reader,
	 sys.Walltime,
	 sys.ClockResolution,
	 sys.Nanotime,
	 sys.ClockResolution,
	 sys.Nanosleep,
	 sys.Osyield,
	 []experimentalsys.FS,  []string,
	 []*net.TCPListener,
) ( *Context,  error) {
	 = &Context{args: , environ: }

	if .argsSize,  = nullTerminatedByteCount(, );  != nil {
		return nil, fmt.Errorf("args invalid: %w", )
	}

	if .environSize,  = nullTerminatedByteCount(, );  != nil {
		return nil, fmt.Errorf("environ invalid: %w", )
	}

	if  == nil {
		.randSource = platform.NewFakeRandSource()
	} else {
		.randSource = 
	}

	if  != nil {
		if clockResolutionInvalid() {
			return nil, fmt.Errorf("invalid Walltime resolution: %d", )
		}
		.walltime = 
		.walltimeResolution = 
	} else {
		.walltime = platform.NewFakeWalltime()
		.walltimeResolution = sys.ClockResolution(time.Microsecond.Nanoseconds())
	}

	if  != nil {
		if clockResolutionInvalid() {
			return nil, fmt.Errorf("invalid Nanotime resolution: %d", )
		}
		.nanotime = 
		.nanotimeResolution = 
	} else {
		.nanotime = platform.NewFakeNanotime()
		.nanotimeResolution = sys.ClockResolution(time.Nanosecond)
	}

	if  != nil {
		.nanosleep = 
	} else {
		.nanosleep = platform.FakeNanosleep
	}

	if  != nil {
		.osyield = 
	} else {
		.osyield = platform.FakeOsyield
	}

	 = .InitFSContext(, , , , , )

	return
}

// clockResolutionInvalid returns true if the value stored isn't reasonable.
func clockResolutionInvalid( sys.ClockResolution) bool {
	return  < 1 ||  > sys.ClockResolution(time.Hour.Nanoseconds())
}

// nullTerminatedByteCount ensures the count or Nul-terminated length of the elements doesn't exceed max, and that no
// element includes the nul character.
func nullTerminatedByteCount( uint32,  [][]byte) (uint32, error) {
	 := uint32(len())
	if  >  {
		return 0, errors.New("exceeds maximum count")
	}

	// The buffer size is the total size including null terminators. The null terminator count == value count, sum
	// count with each value length. This works because in Go, the length of a string is the same as its byte count.
	,  := uint64(), uint64() // uint64 to allow summing without overflow
	for ,  := range  {
		// As this is null-terminated, We have to validate there are no null characters in the string.
		for ,  := range  {
			if  == 0 {
				return 0, errors.New("contains NUL character")
			}
		}

		 :=  + uint64(len())
		if  >  {
			return 0, errors.New("exceeds maximum size")
		}
		 = 

	}
	return uint32(), nil
}