package packets

import (
	"fmt"
	"io"
	"time"
)

// Packet is the base struct for all EverQuest packet types
type Packet struct {
	Buffer []byte
	Opcode uint16

	SrcIP   uint32
	DstIP   uint32
	SrcPort uint16
	DstPort uint16

	Priority  uint32
	Timestamp time.Time
	Version   int16
}

// NewPacket creates a new packet with the given opcode and data
func NewPacket(opcode uint16, data []byte) *Packet {
	p := &Packet{
		Opcode:    opcode,
		Timestamp: time.Now(),
	}
	if len(data) > 0 {
		p.Buffer = make([]byte, len(data))
		copy(p.Buffer, data)
	}
	return p
}

// Size returns the total packet size including opcode
func (p *Packet) Size() uint32 {
	return uint32(len(p.Buffer)) + 2
}

// RawOpcode returns the raw opcode value
func (p *Packet) RawOpcode() uint16 {
	return p.Opcode
}

// SetSrcInfo sets source IP and port
func (p *Packet) SetSrcInfo(ip uint32, port uint16) {
	p.SrcIP = ip
	p.SrcPort = port
}

// SetDstInfo sets destination IP and port
func (p *Packet) SetDstInfo(ip uint32, port uint16) {
	p.DstIP = ip
	p.DstPort = port
}

// CopyInfo copies network and timing info from another packet
func (p *Packet) CopyInfo(other *Packet) {
	p.SrcIP = other.SrcIP
	p.SrcPort = other.SrcPort
	p.DstIP = other.DstIP
	p.DstPort = other.DstPort
	p.Timestamp = other.Timestamp
	p.Version = other.Version
}

// DumpRaw writes packet contents to writer for debugging
func (p *Packet) DumpRaw(w io.Writer) {
	p.DumpRawHeader(0xffff, w)
	if len(p.Buffer) > 0 {
		// TODO: Implement dump_message_column equivalent
		fmt.Fprintf(w, "[Data: %d bytes]\n", len(p.Buffer))
	}
}

// DumpRawHeader writes packet header info to writer
func (p *Packet) DumpRawHeader(seq uint16, w io.Writer) {
	if p.SrcIP != 0 {
		fmt.Fprintf(w, "[%s:%d->%s:%d] ",
			longToIP(p.SrcIP), p.SrcPort,
			longToIP(p.DstIP), p.DstPort)
	}
	if seq != 0xffff {
		fmt.Fprintf(w, "[Seq=%d] ", seq)
	}
	fmt.Fprintf(w, "[OpCode 0x%04x Size=%d]\n", p.Opcode, len(p.Buffer))
}
