package housing

import (
	"encoding/binary"
	"fmt"
	"math"
	"time"
)

// HousingPacketBuilder handles building packets for housing client communication
type HousingPacketBuilder struct {
	clientVersion int
}

// NewHousingPacketBuilder creates a new packet builder
func NewHousingPacketBuilder(clientVersion int) *HousingPacketBuilder {
	return &HousingPacketBuilder{
		clientVersion: clientVersion,
	}
}

// BuildHousePurchasePacket builds the house purchase interface packet
func (hpb *HousingPacketBuilder) BuildHousePurchasePacket(data *HousePurchasePacketData) ([]byte, error) {
	if data == nil {
		return nil, fmt.Errorf("house purchase data is nil")
	}

	// Start with base packet structure
	packet := make([]byte, 0, 512)

	// Packet type identifier
	packet = append(packet, 0x01) // House Purchase packet type

	// House ID (4 bytes)
	houseIDBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(houseIDBytes, uint32(data.HouseID))
	packet = append(packet, houseIDBytes...)

	// House name length and data
	nameBytes := []byte(data.Name)
	packet = append(packet, byte(len(nameBytes)))
	packet = append(packet, nameBytes...)

	// Cost in coins (8 bytes)
	costCoinBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(costCoinBytes, uint64(data.CostCoin))
	packet = append(packet, costCoinBytes...)

	// Cost in status (8 bytes)
	costStatusBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(costStatusBytes, uint64(data.CostStatus))
	packet = append(packet, costStatusBytes...)

	// Upkeep in coins (8 bytes)
	upkeepCoinBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(upkeepCoinBytes, uint64(data.UpkeepCoin))
	packet = append(packet, upkeepCoinBytes...)

	// Upkeep in status (8 bytes)
	upkeepStatusBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(upkeepStatusBytes, uint64(data.UpkeepStatus))
	packet = append(packet, upkeepStatusBytes...)

	// Alignment requirement (1 byte)
	packet = append(packet, byte(data.Alignment))

	// Guild level requirement (1 byte)
	packet = append(packet, byte(data.GuildLevel))

	// Vault slots (4 bytes)
	vaultSlotsBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(vaultSlotsBytes, uint32(data.VaultSlots))
	packet = append(packet, vaultSlotsBytes...)

	// Description length and data
	descBytes := []byte(data.Description)
	descLen := make([]byte, 2)
	binary.LittleEndian.PutUint16(descLen, uint16(len(descBytes)))
	packet = append(packet, descLen...)
	packet = append(packet, descBytes...)

	return packet, nil
}

// BuildHousingListPacket builds the player housing list packet
func (hpb *HousingPacketBuilder) BuildHousingListPacket(data *HouseListPacketData) ([]byte, error) {
	if data == nil {
		return nil, fmt.Errorf("house list data is nil")
	}

	packet := make([]byte, 0, 1024)

	// Packet type identifier
	packet = append(packet, 0x02) // Housing List packet type

	// Number of houses (4 bytes)
	houseCountBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(houseCountBytes, uint32(len(data.Houses)))
	packet = append(packet, houseCountBytes...)

	// House entries
	for _, house := range data.Houses {
		// Unique ID (8 bytes)
		uniqueIDBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(uniqueIDBytes, uint64(house.UniqueID))
		packet = append(packet, uniqueIDBytes...)

		// House name length and data
		nameBytes := []byte(house.Name)
		packet = append(packet, byte(len(nameBytes)))
		packet = append(packet, nameBytes...)

		// House type length and data
		typeBytes := []byte(house.HouseType)
		packet = append(packet, byte(len(typeBytes)))
		packet = append(packet, typeBytes...)

		// Upkeep due timestamp (8 bytes)
		upkeepDueBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(upkeepDueBytes, uint64(house.UpkeepDue.Unix()))
		packet = append(packet, upkeepDueBytes...)

		// Escrow coins (8 bytes)
		escrowCoinsBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(escrowCoinsBytes, uint64(house.EscrowCoins))
		packet = append(packet, escrowCoinsBytes...)

		// Escrow status (8 bytes)
		escrowStatusBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(escrowStatusBytes, uint64(house.EscrowStatus))
		packet = append(packet, escrowStatusBytes...)

		// House status (1 byte)
		packet = append(packet, byte(house.Status))

		// Can enter flag (1 byte)
		if house.CanEnter {
			packet = append(packet, 0x01)
		} else {
			packet = append(packet, 0x00)
		}
	}

	return packet, nil
}

// BuildBaseHouseWindowPacket builds the main house management interface packet
func (hpb *HousingPacketBuilder) BuildBaseHouseWindowPacket(data *BaseHouseWindowPacketData) ([]byte, error) {
	if data == nil {
		return nil, fmt.Errorf("base house window data is nil")
	}

	packet := make([]byte, 0, 2048)

	// Packet type identifier
	packet = append(packet, 0x03) // Base House Window packet type

	// House info
	uniqueIDBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(uniqueIDBytes, uint64(data.HouseInfo.UniqueID))
	packet = append(packet, uniqueIDBytes...)

	// House name
	nameBytes := []byte(data.HouseInfo.Name)
	packet = append(packet, byte(len(nameBytes)))
	packet = append(packet, nameBytes...)

	// House type
	typeBytes := []byte(data.HouseInfo.HouseType)
	packet = append(packet, byte(len(typeBytes)))
	packet = append(packet, typeBytes...)

	// Upkeep due
	upkeepDueBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(upkeepDueBytes, uint64(data.HouseInfo.UpkeepDue.Unix()))
	packet = append(packet, upkeepDueBytes...)

	// Escrow balances
	escrowCoinsBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(escrowCoinsBytes, uint64(data.HouseInfo.EscrowCoins))
	packet = append(packet, escrowCoinsBytes...)

	escrowStatusBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(escrowStatusBytes, uint64(data.HouseInfo.EscrowStatus))
	packet = append(packet, escrowStatusBytes...)

	// Recent deposits count and data
	depositCountBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(depositCountBytes, uint32(len(data.RecentDeposits)))
	packet = append(packet, depositCountBytes...)

	for _, deposit := range data.RecentDeposits {
		// Timestamp (8 bytes)
		timestampBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(timestampBytes, uint64(deposit.Timestamp.Unix()))
		packet = append(packet, timestampBytes...)

		// Amount (8 bytes)
		amountBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(amountBytes, uint64(deposit.Amount))
		packet = append(packet, amountBytes...)

		// Status (8 bytes)
		statusBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(statusBytes, uint64(deposit.Status))
		packet = append(packet, statusBytes...)

		// Player name
		nameBytes := []byte(deposit.Name)
		packet = append(packet, byte(len(nameBytes)))
		packet = append(packet, nameBytes...)
	}

	// Recent history count and data
	historyCountBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(historyCountBytes, uint32(len(data.RecentHistory)))
	packet = append(packet, historyCountBytes...)

	for _, history := range data.RecentHistory {
		// Timestamp (8 bytes)
		timestampBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(timestampBytes, uint64(history.Timestamp.Unix()))
		packet = append(packet, timestampBytes...)

		// Amount (8 bytes)
		amountBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(amountBytes, uint64(history.Amount))
		packet = append(packet, amountBytes...)

		// Status (8 bytes)
		statusBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(statusBytes, uint64(history.Status))
		packet = append(packet, statusBytes...)

		// Positive flag (1 byte)
		packet = append(packet, byte(history.PosFlag))

		// Transaction type (4 bytes)
		typeBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(typeBytes, uint32(history.Type))
		packet = append(packet, typeBytes...)

		// Reason length and data
		reasonBytes := []byte(history.Reason)
		packet = append(packet, byte(len(reasonBytes)))
		packet = append(packet, reasonBytes...)

		// Player name
		nameBytes := []byte(history.Name)
		packet = append(packet, byte(len(nameBytes)))
		packet = append(packet, nameBytes...)
	}

	// Amenities count and data
	amenityCountBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(amenityCountBytes, uint32(len(data.Amenities)))
	packet = append(packet, amenityCountBytes...)

	for _, amenity := range data.Amenities {
		// Amenity ID (4 bytes)
		idBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(idBytes, uint32(amenity.ID))
		packet = append(packet, idBytes...)

		// Type (4 bytes)
		typeBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(typeBytes, uint32(amenity.Type))
		packet = append(packet, typeBytes...)

		// Name
		nameBytes := []byte(amenity.Name)
		packet = append(packet, byte(len(nameBytes)))
		packet = append(packet, nameBytes...)

		// Position (12 bytes - 3 floats)
		xBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(xBytes, math.Float32bits(amenity.X))
		packet = append(packet, xBytes...)

		yBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(yBytes, math.Float32bits(amenity.Y))
		packet = append(packet, yBytes...)

		zBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(zBytes, math.Float32bits(amenity.Z))
		packet = append(packet, zBytes...)

		// Heading (4 bytes)
		headingBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(headingBytes, math.Float32bits(amenity.Heading))
		packet = append(packet, headingBytes...)

		// Is active flag (1 byte)
		if amenity.IsActive {
			packet = append(packet, 0x01)
		} else {
			packet = append(packet, 0x00)
		}
	}

	// House settings
	packet = hpb.appendHouseSettings(packet, data.Settings)

	// Can manage flag (1 byte)
	if data.CanManage {
		packet = append(packet, 0x01)
	} else {
		packet = append(packet, 0x00)
	}

	return packet, nil
}

// BuildHouseVisitPacket builds the house visit interface packet
func (hpb *HousingPacketBuilder) BuildHouseVisitPacket(data *HouseVisitPacketData) ([]byte, error) {
	if data == nil {
		return nil, fmt.Errorf("house visit data is nil")
	}

	packet := make([]byte, 0, 1024)

	// Packet type identifier
	packet = append(packet, 0x04) // House Visit packet type

	// Number of available houses (4 bytes)
	houseCountBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(houseCountBytes, uint32(len(data.AvailableHouses)))
	packet = append(packet, houseCountBytes...)

	// House entries
	for _, house := range data.AvailableHouses {
		// Unique ID (8 bytes)
		uniqueIDBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(uniqueIDBytes, uint64(house.UniqueID))
		packet = append(packet, uniqueIDBytes...)

		// Owner name
		ownerBytes := []byte(house.OwnerName)
		packet = append(packet, byte(len(ownerBytes)))
		packet = append(packet, ownerBytes...)

		// House name
		nameBytes := []byte(house.HouseName)
		packet = append(packet, byte(len(nameBytes)))
		packet = append(packet, nameBytes...)

		// House type
		typeBytes := []byte(house.HouseType)
		packet = append(packet, byte(len(typeBytes)))
		packet = append(packet, typeBytes...)

		// Public note
		noteBytes := []byte(house.PublicNote)
		noteLen := make([]byte, 2)
		binary.LittleEndian.PutUint16(noteLen, uint16(len(noteBytes)))
		packet = append(packet, noteLen...)
		packet = append(packet, noteBytes...)

		// Can visit flag (1 byte)
		if house.CanVisit {
			packet = append(packet, 0x01)
		} else {
			packet = append(packet, 0x00)
		}

		// Requires approval flag (1 byte)
		if house.RequiresApproval {
			packet = append(packet, 0x01)
		} else {
			packet = append(packet, 0x00)
		}
	}

	return packet, nil
}

// BuildHouseUpdatePacket builds a house status update packet
func (hpb *HousingPacketBuilder) BuildHouseUpdatePacket(house *PlayerHouse) ([]byte, error) {
	if house == nil {
		return nil, fmt.Errorf("player house is nil")
	}

	packet := make([]byte, 0, 256)

	// Packet type identifier
	packet = append(packet, 0x05) // House Update packet type

	// Unique ID (8 bytes)
	uniqueIDBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(uniqueIDBytes, uint64(house.UniqueID))
	packet = append(packet, uniqueIDBytes...)

	// Status (1 byte)
	packet = append(packet, byte(house.Status))

	// Upkeep due (8 bytes)
	upkeepDueBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(upkeepDueBytes, uint64(house.UpkeepDue.Unix()))
	packet = append(packet, upkeepDueBytes...)

	// Escrow balances (16 bytes total)
	escrowCoinsBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(escrowCoinsBytes, uint64(house.EscrowCoins))
	packet = append(packet, escrowCoinsBytes...)

	escrowStatusBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(escrowStatusBytes, uint64(house.EscrowStatus))
	packet = append(packet, escrowStatusBytes...)

	return packet, nil
}

// BuildHouseErrorPacket builds an error notification packet
func (hpb *HousingPacketBuilder) BuildHouseErrorPacket(errorCode int, message string) ([]byte, error) {
	packet := make([]byte, 0, 256)

	// Packet type identifier
	packet = append(packet, 0x06) // House Error packet type

	// Error code (4 bytes)
	errorBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(errorBytes, uint32(errorCode))
	packet = append(packet, errorBytes...)

	// Error message length and data
	messageBytes := []byte(message)
	msgLen := make([]byte, 2)
	binary.LittleEndian.PutUint16(msgLen, uint16(len(messageBytes)))
	packet = append(packet, msgLen...)
	packet = append(packet, messageBytes...)

	return packet, nil
}

// BuildHouseDepositPacket builds a deposit confirmation packet
func (hpb *HousingPacketBuilder) BuildHouseDepositPacket(houseID int64, amount int64, status int64, newBalance int64, newStatusBalance int64) ([]byte, error) {
	packet := make([]byte, 0, 64)

	// Packet type identifier
	packet = append(packet, 0x07) // House Deposit packet type

	// House ID (8 bytes)
	houseIDBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(houseIDBytes, uint64(houseID))
	packet = append(packet, houseIDBytes...)

	// Deposit amount (8 bytes)
	amountBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(amountBytes, uint64(amount))
	packet = append(packet, amountBytes...)

	// Status deposit (8 bytes)
	statusBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(statusBytes, uint64(status))
	packet = append(packet, statusBytes...)

	// New coin balance (8 bytes)
	newBalanceBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(newBalanceBytes, uint64(newBalance))
	packet = append(packet, newBalanceBytes...)

	// New status balance (8 bytes)
	newStatusBalanceBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(newStatusBalanceBytes, uint64(newStatusBalance))
	packet = append(packet, newStatusBalanceBytes...)

	return packet, nil
}

// BuildHouseWithdrawalPacket builds a withdrawal confirmation packet
func (hpb *HousingPacketBuilder) BuildHouseWithdrawalPacket(houseID int64, amount int64, status int64, newBalance int64, newStatusBalance int64) ([]byte, error) {
	packet := make([]byte, 0, 64)

	// Packet type identifier
	packet = append(packet, 0x08) // House Withdrawal packet type

	// House ID (8 bytes)
	houseIDBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(houseIDBytes, uint64(houseID))
	packet = append(packet, houseIDBytes...)

	// Withdrawal amount (8 bytes)
	amountBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(amountBytes, uint64(amount))
	packet = append(packet, amountBytes...)

	// Status withdrawal (8 bytes)
	statusBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(statusBytes, uint64(status))
	packet = append(packet, statusBytes...)

	// New coin balance (8 bytes)
	newBalanceBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(newBalanceBytes, uint64(newBalance))
	packet = append(packet, newBalanceBytes...)

	// New status balance (8 bytes)
	newStatusBalanceBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(newStatusBalanceBytes, uint64(newStatusBalance))
	packet = append(packet, newStatusBalanceBytes...)

	return packet, nil
}

// BuildItemPlacementPacket builds an item placement response packet
func (hpb *HousingPacketBuilder) BuildItemPlacementPacket(item *HouseItem, success bool) ([]byte, error) {
	if item == nil {
		return nil, fmt.Errorf("house item is nil")
	}

	packet := make([]byte, 0, 128)

	// Packet type identifier
	packet = append(packet, 0x09) // Item Placement packet type

	// Item ID (8 bytes)
	itemIDBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(itemIDBytes, uint64(item.ID))
	packet = append(packet, itemIDBytes...)

	// Success flag (1 byte)
	if success {
		packet = append(packet, 0x01)
	} else {
		packet = append(packet, 0x00)
	}

	if success {
		// Position (12 bytes - 3 floats)
		xBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(xBytes, math.Float32bits(item.X))
		packet = append(packet, xBytes...)

		yBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(yBytes, math.Float32bits(item.Y))
		packet = append(packet, yBytes...)

		zBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(zBytes, math.Float32bits(item.Z))
		packet = append(packet, zBytes...)

		// Heading (4 bytes)
		headingBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(headingBytes, math.Float32bits(item.Heading))
		packet = append(packet, headingBytes...)

		// Pitch/Roll (16 bytes - 4 floats)
		pitchXBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(pitchXBytes, math.Float32bits(item.PitchX))
		packet = append(packet, pitchXBytes...)

		pitchYBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(pitchYBytes, math.Float32bits(item.PitchY))
		packet = append(packet, pitchYBytes...)

		rollXBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(rollXBytes, math.Float32bits(item.RollX))
		packet = append(packet, rollXBytes...)

		rollYBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(rollYBytes, math.Float32bits(item.RollY))
		packet = append(packet, rollYBytes...)
	}

	return packet, nil
}

// BuildAccessUpdatePacket builds an access permission update packet
func (hpb *HousingPacketBuilder) BuildAccessUpdatePacket(houseID int64, access []HouseAccess) ([]byte, error) {
	packet := make([]byte, 0, 1024)

	// Packet type identifier
	packet = append(packet, 0x0A) // Access Update packet type

	// House ID (8 bytes)
	houseIDBytes := make([]byte, 8)
	binary.LittleEndian.PutUint64(houseIDBytes, uint64(houseID))
	packet = append(packet, houseIDBytes...)

	// Access entry count (4 bytes)
	countBytes := make([]byte, 4)
	binary.LittleEndian.PutUint32(countBytes, uint32(len(access)))
	packet = append(packet, countBytes...)

	// Access entries
	for _, entry := range access {
		// Character ID (4 bytes)
		charIDBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(charIDBytes, uint32(entry.CharacterID))
		packet = append(packet, charIDBytes...)

		// Player name
		nameBytes := []byte(entry.PlayerName)
		packet = append(packet, byte(len(nameBytes)))
		packet = append(packet, nameBytes...)

		// Access level (1 byte)
		packet = append(packet, byte(entry.AccessLevel))

		// Permissions (4 bytes)
		permBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(permBytes, uint32(entry.Permissions))
		packet = append(packet, permBytes...)

		// Granted by (4 bytes)
		grantedByBytes := make([]byte, 4)
		binary.LittleEndian.PutUint32(grantedByBytes, uint32(entry.GrantedBy))
		packet = append(packet, grantedByBytes...)

		// Granted date (8 bytes)
		grantedDateBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(grantedDateBytes, uint64(entry.GrantedDate.Unix()))
		packet = append(packet, grantedDateBytes...)

		// Expires date (8 bytes)
		expiresDateBytes := make([]byte, 8)
		binary.LittleEndian.PutUint64(expiresDateBytes, uint64(entry.ExpiresDate.Unix()))
		packet = append(packet, expiresDateBytes...)

		// Notes
		notesBytes := []byte(entry.Notes)
		notesLen := make([]byte, 2)
		binary.LittleEndian.PutUint16(notesLen, uint16(len(notesBytes)))
		packet = append(packet, notesLen...)
		packet = append(packet, notesBytes...)
	}

	return packet, nil
}

// Helper methods

// appendHouseSettings appends house settings to a packet
func (hpb *HousingPacketBuilder) appendHouseSettings(packet []byte, settings HouseSettings) []byte {
	// House name
	nameBytes := []byte(settings.HouseName)
	packet = append(packet, byte(len(nameBytes)))
	packet = append(packet, nameBytes...)

	// Visit permission (1 byte)
	packet = append(packet, byte(settings.VisitPermission))

	// Public note
	publicNoteBytes := []byte(settings.PublicNote)
	publicNoteLen := make([]byte, 2)
	binary.LittleEndian.PutUint16(publicNoteLen, uint16(len(publicNoteBytes)))
	packet = append(packet, publicNoteLen...)
	packet = append(packet, publicNoteBytes...)

	// Private note
	privateNoteBytes := []byte(settings.PrivateNote)
	privateNoteLen := make([]byte, 2)
	binary.LittleEndian.PutUint16(privateNoteLen, uint16(len(privateNoteBytes)))
	packet = append(packet, privateNoteLen...)
	packet = append(packet, privateNoteBytes...)

	// Boolean flags (6 bytes)
	flags := []bool{
		settings.AllowFriends,
		settings.AllowGuild,
		settings.RequireApproval,
		settings.ShowOnDirectory,
		settings.AllowDecoration,
		settings.TaxExempt,
	}

	for _, flag := range flags {
		if flag {
			packet = append(packet, 0x01)
		} else {
			packet = append(packet, 0x00)
		}
	}

	return packet
}

// ValidatePacketSize checks if packet size is within acceptable limits
func (hpb *HousingPacketBuilder) ValidatePacketSize(packet []byte) error {
	maxSize := hpb.getMaxPacketSize()

	if len(packet) > maxSize {
		return fmt.Errorf("packet size %d exceeds maximum %d", len(packet), maxSize)
	}

	return nil
}

// getMaxPacketSize returns the maximum packet size for the client version
func (hpb *HousingPacketBuilder) getMaxPacketSize() int {
	if hpb.clientVersion >= 564 {
		return 4096 // Newer clients support larger packets
	}
	return 2048 // Older clients have smaller limits
}

// GetPacketTypeDescription returns human-readable packet type description
func (hpb *HousingPacketBuilder) GetPacketTypeDescription(packetType byte) string {
	switch packetType {
	case 0x01:
		return "House Purchase"
	case 0x02:
		return "Housing List"
	case 0x03:
		return "Base House Window"
	case 0x04:
		return "House Visit"
	case 0x05:
		return "House Update"
	case 0x06:
		return "House Error"
	case 0x07:
		return "House Deposit"
	case 0x08:
		return "House Withdrawal"
	case 0x09:
		return "Item Placement"
	case 0x0A:
		return "Access Update"
	default:
		return "Unknown"
	}
}

// Client version specific methods

// IsVersionSupported checks if client version supports specific features
func (hpb *HousingPacketBuilder) IsVersionSupported(feature string) bool {
	switch feature {
	case "extended_access":
		return hpb.clientVersion >= 546
	case "amenity_management":
		return hpb.clientVersion >= 564
	case "item_rotation":
		return hpb.clientVersion >= 572
	case "house_search":
		return hpb.clientVersion >= 580
	default:
		return true // Basic features supported in all versions
	}
}

// Error codes for housing system
const (
	HouseErrorNone = iota
	HouseErrorInsufficientFunds
	HouseErrorInsufficientStatus
	HouseErrorAccessDenied
	HouseErrorHouseNotFound
	HouseErrorAlignmentRestriction
	HouseErrorGuildLevelRestriction
	HouseErrorUpkeepOverdue
	HouseErrorMaxHousesReached
	HouseErrorInvalidPlacement
	HouseErrorItemNotFound
	HouseErrorSystemDisabled
)

// getHousingErrorMessage returns human-readable error message for error code
func getHousingErrorMessage(errorCode int) string {
	switch errorCode {
	case HouseErrorNone:
		return "No error"
	case HouseErrorInsufficientFunds:
		return "Insufficient funds"
	case HouseErrorInsufficientStatus:
		return "Insufficient status points"
	case HouseErrorAccessDenied:
		return "Access denied"
	case HouseErrorHouseNotFound:
		return "House not found"
	case HouseErrorAlignmentRestriction:
		return "Alignment requirement not met"
	case HouseErrorGuildLevelRestriction:
		return "Guild level requirement not met"
	case HouseErrorUpkeepOverdue:
		return "House upkeep is overdue"
	case HouseErrorMaxHousesReached:
		return "Maximum number of houses reached"
	case HouseErrorInvalidPlacement:
		return "Invalid item placement"
	case HouseErrorItemNotFound:
		return "Item not found"
	case HouseErrorSystemDisabled:
		return "Housing system is disabled"
	default:
		return "Unknown error"
	}
}

// Packet parsing helper methods for incoming packets

// ParseBuyHousePacket parses an incoming buy house request
func (hpb *HousingPacketBuilder) ParseBuyHousePacket(data []byte) (int32, error) {
	if len(data) < 4 {
		return 0, fmt.Errorf("packet too short for buy house request")
	}

	// Extract house ID (4 bytes)
	houseID := int32(binary.LittleEndian.Uint32(data[0:4]))

	return houseID, nil
}

// ParseEnterHousePacket parses an incoming enter house request
func (hpb *HousingPacketBuilder) ParseEnterHousePacket(data []byte) (int64, error) {
	if len(data) < 8 {
		return 0, fmt.Errorf("packet too short for enter house request")
	}

	// Extract unique house ID (8 bytes)
	uniqueID := int64(binary.LittleEndian.Uint64(data[0:8]))

	return uniqueID, nil
}

// ParseDepositPacket parses an incoming deposit request
func (hpb *HousingPacketBuilder) ParseDepositPacket(data []byte) (int64, int64, int64, error) {
	if len(data) < 24 {
		return 0, 0, 0, fmt.Errorf("packet too short for deposit request")
	}

	// Extract house ID (8 bytes)
	houseID := int64(binary.LittleEndian.Uint64(data[0:8]))

	// Extract coin amount (8 bytes)
	coinAmount := int64(binary.LittleEndian.Uint64(data[8:16]))

	// Extract status amount (8 bytes)
	statusAmount := int64(binary.LittleEndian.Uint64(data[16:24]))

	return houseID, coinAmount, statusAmount, nil
}

// Time formatting helpers for display

// FormatUpkeepDue formats upkeep due date for display
func FormatUpkeepDue(upkeepDue time.Time) string {
	now := time.Now()

	if upkeepDue.Before(now) {
		duration := now.Sub(upkeepDue)
		days := int(duration.Hours() / 24)
		if days == 0 {
			return "Overdue (today)"
		}
		return fmt.Sprintf("Overdue (%d days)", days)
	} else {
		duration := upkeepDue.Sub(now)
		days := int(duration.Hours() / 24)
		if days == 0 {
			return "Due today"
		}
		return fmt.Sprintf("Due in %d days", days)
	}
}

// FormatCurrency formats currency amounts for display
func FormatCurrency(amount int64) string {
	if amount < 0 {
		return fmt.Sprintf("-%s", FormatCurrency(-amount))
	}

	if amount >= 10000 { // 1 gold = 10000 copper
		gold := amount / 10000
		remainder := amount % 10000
		if remainder == 0 {
			return fmt.Sprintf("%dg", gold)
		} else {
			silver := remainder / 100
			copper := remainder % 100
			if copper == 0 {
				return fmt.Sprintf("%dg %ds", gold, silver)
			} else {
				return fmt.Sprintf("%dg %ds %dc", gold, silver, copper)
			}
		}
	} else if amount >= 100 {
		silver := amount / 100
		copper := amount % 100
		if copper == 0 {
			return fmt.Sprintf("%ds", silver)
		} else {
			return fmt.Sprintf("%ds %dc", silver, copper)
		}
	} else {
		return fmt.Sprintf("%dc", amount)
	}
}
