package types

import (
	"encoding/binary"
	"io"
)

// EQ2String8 represents a string with an 8-bit length prefix
type EQ2String8 string

// Serialize writes the string with 8-bit length prefix
func (s EQ2String8) Serialize(w io.Writer) error {
	if len(s) > 255 {
		return io.ErrShortWrite
	}
	
	// Write length byte
	if err := binary.Write(w, binary.LittleEndian, uint8(len(s))); err != nil {
		return err
	}
	
	// Write string data
	_, err := w.Write([]byte(s))
	return err
}

// SerializeToBytes writes the string to a byte slice at the given offset
func (s EQ2String8) SerializeToBytes(dest []byte, offset *uint32) {
	dest[*offset] = uint8(len(s))
	*offset++
	copy(dest[*offset:], []byte(s))
	*offset += uint32(len(s))
}

// Size returns the serialized size (1 byte length + string data)
func (s EQ2String8) Size() uint32 {
	return 1 + uint32(len(s))
}

// Deserialize reads a string with 8-bit length prefix
func (s *EQ2String8) Deserialize(r io.Reader) error {
	var length uint8
	if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
		return err
	}
	
	data := make([]byte, length)
	if _, err := io.ReadFull(r, data); err != nil {
		return err
	}
	
	*s = EQ2String8(data)
	return nil
}

// EQ2String16 represents a string with a 16-bit length prefix
type EQ2String16 string

// Serialize writes the string with 16-bit length prefix
func (s EQ2String16) Serialize(w io.Writer) error {
	if len(s) > 65535 {
		return io.ErrShortWrite
	}
	
	// Write length as uint16
	if err := binary.Write(w, binary.LittleEndian, uint16(len(s))); err != nil {
		return err
	}
	
	// Write string data
	_, err := w.Write([]byte(s))
	return err
}

// SerializeToBytes writes the string to a byte slice at the given offset
func (s EQ2String16) SerializeToBytes(dest []byte, offset *uint32) {
	binary.LittleEndian.PutUint16(dest[*offset:], uint16(len(s)))
	*offset += 2
	copy(dest[*offset:], []byte(s))
	*offset += uint32(len(s))
}

// Size returns the serialized size (2 bytes length + string data)
func (s EQ2String16) Size() uint32 {
	return 2 + uint32(len(s))
}

// Deserialize reads a string with 16-bit length prefix
func (s *EQ2String16) Deserialize(r io.Reader) error {
	var length uint16
	if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
		return err
	}
	
	data := make([]byte, length)
	if _, err := io.ReadFull(r, data); err != nil {
		return err
	}
	
	*s = EQ2String16(data)
	return nil
}

// EQ2String32 represents a string with a 32-bit length prefix
type EQ2String32 string

// Serialize writes the string with 32-bit length prefix
func (s EQ2String32) Serialize(w io.Writer) error {
	// Write length as uint32
	if err := binary.Write(w, binary.LittleEndian, uint32(len(s))); err != nil {
		return err
	}
	
	// Write string data
	_, err := w.Write([]byte(s))
	return err
}

// SerializeToBytes writes the string to a byte slice at the given offset
func (s EQ2String32) SerializeToBytes(dest []byte, offset *uint32) {
	binary.LittleEndian.PutUint32(dest[*offset:], uint32(len(s)))
	*offset += 4
	copy(dest[*offset:], []byte(s))
	*offset += uint32(len(s))
}

// Size returns the serialized size (4 bytes length + string data)
func (s EQ2String32) Size() uint32 {
	return 4 + uint32(len(s))
}

// Deserialize reads a string with 32-bit length prefix
func (s *EQ2String32) Deserialize(r io.Reader) error {
	var length uint32
	if err := binary.Read(r, binary.LittleEndian, &length); err != nil {
		return err
	}
	
	// Sanity check to prevent huge allocations
	if length > 1024*1024 { // 1MB limit
		return io.ErrUnexpectedEOF
	}
	
	data := make([]byte, length)
	if _, err := io.ReadFull(r, data); err != nil {
		return err
	}
	
	*s = EQ2String32(data)
	return nil
}