package model

import "encoding/json"

// WSEnvelope is the wire format for all WebSocket messages (both directions).
type WSEnvelope struct {
	Type    string          `json:"type"`
	Payload json.RawMessage `json:"payload"`
}

// NewWSEnvelope creates an envelope by marshaling the payload to JSON.
// If marshaling fails, payload is set to "{}".
func NewWSEnvelope(msgType string, payload any) WSEnvelope {
	raw, err := json.Marshal(payload)
	if err != nil {
		raw = []byte("{}")
	}
	return WSEnvelope{Type: msgType, Payload: raw}
}

// ClientMessage is a parsed inbound message from a WebSocket client,
// tagged with the hero ID of the sending connection.
type ClientMessage struct {
	HeroID  int64
	Type    string
	Payload json.RawMessage
}

// --- Server -> Client payload types ---

// HeroMovePayload is sent on the configured movement cadence while the hero is walking.
type HeroMovePayload struct {
	X       float64 `json:"x"`
	Y       float64 `json:"y"`
	TargetX float64 `json:"targetX"`
	TargetY float64 `json:"targetY"`
	Speed   float64 `json:"speed"`
	Heading float64 `json:"heading"` // radians
}

// PositionSyncPayload is sent on the configured sync cadence as drift correction.
type PositionSyncPayload struct {
	X                float64 `json:"x"`
	Y                float64 `json:"y"`
	WaypointIndex    int     `json:"waypointIndex"`
	WaypointFraction float64 `json:"waypointFraction"`
	State            string  `json:"state"`
}

// RouteAssignedPayload is sent when the hero starts walking a new road segment.
type RouteAssignedPayload struct {
	RoadID            int64      `json:"roadId"`
	Waypoints         []PointXY  `json:"waypoints"`
	DestinationTownID int64      `json:"destinationTownId"`
	Speed             float64    `json:"speed"`
}

// PointXY is a 2D coordinate used in route payloads.
type PointXY struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

// CombatStartPayload is sent when combat begins.
type CombatStartPayload struct {
	Enemy CombatEnemyInfo `json:"enemy"`
}

// CombatEnemyInfo is the enemy snapshot sent to the client on combat_start.
type CombatEnemyInfo struct {
	Name    string  `json:"name"`
	Type    string  `json:"type"`
	HP      int     `json:"hp"`
	MaxHP   int     `json:"maxHp"`
	Attack  int     `json:"attack"`
	Defense int     `json:"defense"`
	Speed   float64 `json:"speed"`
	IsElite bool    `json:"isElite"`
}

// AttackPayload is sent on each swing during combat.
type AttackPayload struct {
	Source        string `json:"source"` // "hero" or "enemy"
	Damage        int    `json:"damage"`
	IsCrit        bool   `json:"isCrit,omitempty"`
	HeroHP        int    `json:"heroHp"`
	EnemyHP       int    `json:"enemyHp"`
	DebuffApplied string `json:"debuffApplied,omitempty"`
}

// CombatEndPayload is sent when the hero wins a fight.
type CombatEndPayload struct {
	XPGained   int64       `json:"xpGained"`
	GoldGained int64       `json:"goldGained"`
	Loot       []LootItem  `json:"loot,omitempty"`
	LeveledUp  bool        `json:"leveledUp"`
	NewLevel   int         `json:"newLevel,omitempty"`
}

// LootItem describes a single piece of loot in the combat_end payload.
type LootItem struct {
	ItemType string `json:"itemType"`
	Name     string `json:"name"`
	Rarity   string `json:"rarity"`
}

// HeroDiedPayload is sent when the hero's HP reaches 0.
type HeroDiedPayload struct {
	KilledBy string `json:"killedBy"`
}

// HeroRevivedPayload is sent after a revive.
type HeroRevivedPayload struct {
	HP int `json:"hp"`
}

// TownNPCInfo describes an NPC in a town (town_enter payload).
type TownNPCInfo struct {
	ID         int64  `json:"id"`
	Name       string `json:"name"`
	Type       string `json:"type"`
	BuildingID *int64 `json:"buildingId,omitempty"`
}

// TownBuildingInfo describes a building in a town (town_enter payload).
type TownBuildingInfo struct {
	ID           int64   `json:"id"`
	BuildingType string  `json:"buildingType"`
	WorldX       float64 `json:"worldX"`
	WorldY       float64 `json:"worldY"`
	Facing       string  `json:"facing"`
	FootprintW   float64 `json:"footprintW"`
	FootprintH   float64 `json:"footprintH"`
}

// TownEnterPayload is sent when a hero arrives at a town.
type TownEnterPayload struct {
	TownID         int64              `json:"townId"`
	TownName       string             `json:"townName"`
	Biome          string             `json:"biome"`
	NPCs           []TownNPCInfo      `json:"npcs"`
	Buildings      []TownBuildingInfo `json:"buildings"`
	RestDurationMs int64              `json:"restDurationMs"`
}

// TownNPCVisitPayload is sent when the hero approaches an NPC (quest/shop/healer) during a town stay.
type TownNPCVisitPayload struct {
	NPCID  int64  `json:"npcId"`
	Name   string `json:"name"`
	Type   string `json:"type"`
	TownID int64  `json:"townId"`
}

// AdventureLogLinePayload is sent when a new line is appended to the hero's adventure log.
type AdventureLogLinePayload struct {
	Message string `json:"message"`
}

// TownExitPayload is sent when the hero leaves a town.
type TownExitPayload struct{}

// MerchantLootPayload is sent after a successful wandering merchant trade (WS or REST when online).
type MerchantLootPayload struct {
	GoldSpent  int64  `json:"goldSpent"`
	ItemType   string `json:"itemType"` // "potion", equipment slot key, etc.
	ItemName   string `json:"itemName,omitempty"`
	Rarity     string `json:"rarity,omitempty"`
	GoldAmount int64  `json:"goldAmount,omitempty"` // auto-sell gold
}

// NPCEncounterPayload is sent when the hero meets a wandering NPC on the road (e.g. merchant).
type NPCEncounterPayload struct {
	NPCID    int64  `json:"npcId"`
	NPCName  string `json:"npcName"`
	Role     string `json:"role"`
	Dialogue string `json:"dialogue,omitempty"`
	Cost     int64  `json:"cost"`
}

// NPCEncounterEndPayload is sent when the wandering merchant prompt ends (e.g. timeout).
type NPCEncounterEndPayload struct {
	Reason string `json:"reason"` // "timeout"
}

// LevelUpPayload is sent on level-up.
type LevelUpPayload struct {
	NewLevel int `json:"newLevel"`
}

// BuffAppliedPayload is sent when a buff is activated.
type BuffAppliedPayload struct {
	BuffType  string  `json:"buffType"`
	Duration  float64 `json:"duration"` // seconds
	Magnitude float64 `json:"magnitude"`
}

// ErrorPayload is sent when a client command fails validation.
type ErrorPayload struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

// --- Client -> Server payload types ---

// ActivateBuffPayload is the payload for the activate_buff command.
type ActivateBuffPayload struct {
	BuffType string `json:"buffType"`
}

// AcceptQuestPayload is the payload for the accept_quest command.
type AcceptQuestPayload struct {
	QuestID int64 `json:"questId"`
}

// ClaimQuestPayload is the payload for the claim_quest command.
type ClaimQuestPayload struct {
	QuestID int64 `json:"questId"`
}

// NPCInteractPayload is the payload for the npc_interact command.
type NPCInteractPayload struct {
	NPCID int64 `json:"npcId"`
}

// ExcursionStartPayload is sent when a mini-adventure begins.
type ExcursionStartPayload struct {
	DepthWorldUnits float64 `json:"depthWorldUnits"`
}

// ExcursionPhasePayload is sent when the excursion transitions between phases.
type ExcursionPhasePayload struct {
	Phase string `json:"phase"`
}

// ExcursionEndPayload is sent when the mini-adventure completes.
type ExcursionEndPayload struct{}
