package tuning

import (
	"context"
	"encoding/json"
	"log/slog"
	"sync/atomic"
	"time"
)

// Values contains runtime-tunable gameplay knobs loaded from DB.
// Missing JSON fields keep default values.
type Values struct {
	EncounterCooldownBaseMs int64   `json:"encounterCooldownBaseMs"`
	EncounterActivityBase   float64 `json:"encounterActivityBase"`

	BaseMoveSpeed     float64 `json:"baseMoveSpeed"`
	MovementTickRateMs int64  `json:"movementTickRateMs"`
	PositionSyncRateMs int64  `json:"positionSyncRateMs"`

	TownRestMinMs      int64   `json:"townRestMinMs"`
	TownRestMaxMs      int64   `json:"townRestMaxMs"`
	TownRestHPPerS     float64 `json:"townRestHpPerSecond"`
	TownArrivalRadius  float64 `json:"townArrivalRadius"`
	TownNPCVisitChance float64 `json:"townNpcVisitChance"`
	TownNPCRollMinMs   int64   `json:"townNpcRollMinMs"`
	TownNPCRollMaxMs   int64   `json:"townNpcRollMaxMs"`
	TownNPCRetryMs     int64   `json:"townNpcRetryMs"`
	TownNPCPauseMs     int64   `json:"townNpcPauseMs"`
	TownNPCLogIntervalMs int64 `json:"townNpcLogIntervalMs"`

	WanderingMerchantPromptTimeoutMs int64   `json:"wanderingMerchantPromptTimeoutMs"`
	MerchantCostBase                 int64   `json:"merchantCostBase"`
	MerchantCostPerLevel             int64   `json:"merchantCostPerLevel"`
	MerchantTownAutoSellShare        float64 `json:"merchantTownAutoSellShare"`
	MonsterEncounterWeightBase       float64 `json:"monsterEncounterWeightBase"`
	MonsterEncounterWeightWildBonus  float64 `json:"monsterEncounterWeightWildBonus"`
	MerchantEncounterWeightBase      float64 `json:"merchantEncounterWeightBase"`
	MerchantEncounterWeightRoadBonus float64 `json:"merchantEncounterWeightRoadBonus"`

	LootChanceCommon    float64 `json:"lootChanceCommon"`
	LootChanceUncommon  float64 `json:"lootChanceUncommon"`
	LootChanceRare      float64 `json:"lootChanceRare"`
	LootChanceEpic      float64 `json:"lootChanceEpic"`
	LootChanceLegendary float64 `json:"lootChanceLegendary"`
	GoldLootScale       float64 `json:"goldLootScale"`
	PotionDropChance    float64 `json:"potionDropChance"`
	EquipmentDropBase   float64 `json:"equipmentDropBase"`

	GoldCommonMin int64 `json:"goldCommonMin"`
	GoldCommonMax int64 `json:"goldCommonMax"`
	GoldUncommonMin int64 `json:"goldUncommonMin"`
	GoldUncommonMax int64 `json:"goldUncommonMax"`
	GoldRareMin int64 `json:"goldRareMin"`
	GoldRareMax int64 `json:"goldRareMax"`
	GoldEpicMin int64 `json:"goldEpicMin"`
	GoldEpicMax int64 `json:"goldEpicMax"`
	GoldLegendaryMin int64 `json:"goldLegendaryMin"`
	GoldLegendaryMax int64 `json:"goldLegendaryMax"`

	AutoSellCommon    int64 `json:"autoSellCommon"`
	AutoSellUncommon  int64 `json:"autoSellUncommon"`
	AutoSellRare      int64 `json:"autoSellRare"`
	AutoSellEpic      int64 `json:"autoSellEpic"`
	AutoSellLegendary int64 `json:"autoSellLegendary"`

	RESTEncounterCooldownMs int64   `json:"restEncounterCooldownMs"`
	RESTEncounterNPCChance  float64 `json:"restEncounterNpcChance"`
	NPCCostHeal             int64   `json:"npcCostHeal"`
	NPCCostPotion           int64   `json:"npcCostPotion"`
	NPCCostNearbyRadius     float64 `json:"npcCostNearbyRadius"`

	CombatDamageScale      float64 `json:"combatDamageScale"`
	EnemyDodgeChance       float64 `json:"enemyDodgeChance"`
	EnemyCriticalMinChance float64 `json:"enemyCriticalMinChance"`
	EnemyBurstEveryN       int64   `json:"enemyBurstEveryN"`
	EnemyBurstMultiplier   float64 `json:"enemyBurstMultiplier"`
	EnemyChainEveryN       int64   `json:"enemyChainEveryN"`
	EnemyChainMultiplier   float64 `json:"enemyChainMultiplier"`

	DebuffProcBurn    float64 `json:"debuffProcBurn"`
	DebuffProcPoison  float64 `json:"debuffProcPoison"`
	DebuffProcSlow    float64 `json:"debuffProcSlow"`
	DebuffProcStun    float64 `json:"debuffProcStun"`
	DebuffProcFreeze  float64 `json:"debuffProcFreeze"`
	DebuffProcIceSlow float64 `json:"debuffProcIceSlow"`

	EnemyRegenDefault       float64 `json:"enemyRegenDefault"`
	EnemyRegenSkeletonKing  float64 `json:"enemyRegenSkeletonKing"`
	EnemyRegenForestWarden  float64 `json:"enemyRegenForestWarden"`
	EnemyRegenBattleLizard  float64 `json:"enemyRegenBattleLizard"`
	SummonCycleSeconds      int64   `json:"summonCycleSeconds"`
	SummonDamageDivisor     int64   `json:"summonDamageDivisor"`
	LuckBuffMultiplier      float64 `json:"luckBuffMultiplier"`

	MinAttackIntervalMs int64 `json:"minAttackIntervalMs"`
	CombatPaceMultiplier int64 `json:"combatPaceMultiplier"`

	PotionHealPercent          float64 `json:"potionHealPercent"`
	PotionAutoUseThreshold     float64 `json:"potionAutoUseThreshold"`
	ReviveHpPercent            float64 `json:"reviveHpPercent"`
	AutoReviveAfterMs          int64   `json:"autoReviveAfterMs"`

	XPCurveEarlyBase  float64 `json:"xpCurveEarlyBase"`
	XPCurveEarlyScale float64 `json:"xpCurveEarlyScale"`
	XPCurveMidBase    float64 `json:"xpCurveMidBase"`
	XPCurveMidScale   float64 `json:"xpCurveMidScale"`
	XPCurveLateBase   float64 `json:"xpCurveLateBase"`
	XPCurveLateScale  float64 `json:"xpCurveLateScale"`

	LevelUpHPEvery int64 `json:"levelUpHpEvery"`
	LevelUpATKEvery int64 `json:"levelUpAtkEvery"`
	LevelUpDEFEvery int64 `json:"levelUpDefEvery"`
	LevelUpSTREvery int64 `json:"levelUpStrEvery"`
	LevelUpCONEvery int64 `json:"levelUpConEvery"`
	LevelUpAGIEvery int64 `json:"levelUpAgiEvery"`
	LevelUpLUCKEvery int64 `json:"levelUpLuckEvery"`

	AgilityCoef   float64 `json:"agilityCoef"`
	MaxAttackSpeed float64 `json:"maxAttackSpeed"`
	MinAttackSpeed float64 `json:"minAttackSpeed"`

	IlvlFactorSlope float64 `json:"ilvlFactorSlope"`
	RarityMultiplierCommon    float64 `json:"rarityMultiplierCommon"`
	RarityMultiplierUncommon  float64 `json:"rarityMultiplierUncommon"`
	RarityMultiplierRare      float64 `json:"rarityMultiplierRare"`
	RarityMultiplierEpic      float64 `json:"rarityMultiplierEpic"`
	RarityMultiplierLegendary float64 `json:"rarityMultiplierLegendary"`
	RollIlvlEliteBaseChance   float64 `json:"rollIlvlEliteBaseChance"`
	RollIlvlElitePlusOneChance float64 `json:"rollIlvlElitePlusOneChance"`

	BuffChargePeriodMs int64 `json:"buffChargePeriodMs"`
	FreeBuffActivationsPerPeriod int64 `json:"freeBuffActivationsPerPeriod"`
	SubscriptionDurationMs int64 `json:"subscriptionDurationMs"`
	SubscriptionWeeklyPriceRUB int64 `json:"subscriptionWeeklyPriceRub"`
	BuffRefillPriceRUB int64 `json:"buffRefillPriceRub"`
	ResurrectionRefillPriceRUB int64 `json:"resurrectionRefillPriceRub"`
	MaxRevivesFree int64 `json:"maxRevivesFree"`
	MaxRevivesSubscriber int64 `json:"maxRevivesSubscriber"`

	EnemyScaleBandHP      float64 `json:"enemyScaleBandHp"`
	EnemyScaleOvercapHP   float64 `json:"enemyScaleOvercapHp"`
	EnemyScaleBandATK     float64 `json:"enemyScaleBandAtk"`
	EnemyScaleOvercapATK  float64 `json:"enemyScaleOvercapAtk"`
	EnemyScaleBandDEF     float64 `json:"enemyScaleBandDef"`
	EnemyScaleOvercapDEF  float64 `json:"enemyScaleOvercapDef"`
	EnemyScaleBandXP      float64 `json:"enemyScaleBandXp"`
	EnemyScaleOvercapXP   float64 `json:"enemyScaleOvercapXp"`
	EnemyScaleBandGold    float64 `json:"enemyScaleBandGold"`
	EnemyScaleOvercapGold float64 `json:"enemyScaleOvercapGold"`

	AutoEquipThreshold float64 `json:"autoEquipThreshold"`
	LootHistoryLimit   int64   `json:"lootHistoryLimit"`

	// --- Adventure / excursion (mini-adventure off-road) ---

	// AdventureStartChance is the per-tick probability of starting an adventure while walking.
	// With 500ms ticks and ~50% walking uptime, 0.0001 ≈ 3 adventures per 8 h.
	AdventureStartChance float64 `json:"adventureStartChance"`
	// AdventureCooldownMs is the minimum wall-time between two adventure sessions.
	AdventureCooldownMs int64 `json:"adventureCooldownMs"`
	// AdventureOutDurationMs is how long the "out" phase lasts (hero moves off-road into forest).
	AdventureOutDurationMs int64 `json:"adventureOutDurationMs"`
	// AdventureWildMinMs / AdventureWildMaxMs define the random range for the "wild" phase
	// (encounters in the forest). Total adventure ≈ out + wild + return.
	AdventureWildMinMs int64 `json:"adventureWildMinMs"`
	AdventureWildMaxMs int64 `json:"adventureWildMaxMs"`
	// AdventureReturnDurationMs is how long the "return" phase lasts (hero walks back to road).
	AdventureReturnDurationMs int64 `json:"adventureReturnDurationMs"`
	// AdventureDepthWorldUnits is the max perpendicular offset from road during an adventure.
	AdventureDepthWorldUnits float64 `json:"adventureDepthWorldUnits"`
	// AdventureEncounterCooldownMs is the encounter cooldown while in the wild/return phases.
	AdventureEncounterCooldownMs int64 `json:"adventureEncounterCooldownMs"`
	// AdventureReturnEncounterEnabled allows encounters during the return phase.
	AdventureReturnEncounterEnabled bool `json:"adventureReturnEncounterEnabled"`

	// --- HP-based rest triggers ---

	// LowHpThreshold is the HP/MaxHP fraction below which rest may trigger (0..1).
	LowHpThreshold float64 `json:"lowHpThreshold"`
	// RoadsideRestExitHp is the HP/MaxHP fraction at which roadside rest ends early (0..1).
	RoadsideRestExitHp float64 `json:"roadsideRestExitHp"`
	// AdventureRestTargetHp is the HP/MaxHP fraction at which adventure inline rest ends (0..1).
	AdventureRestTargetHp float64 `json:"adventureRestTargetHp"`
	// RoadsideRestMinMs is the minimum duration for a roadside rest period.
	RoadsideRestMinMs int64 `json:"roadsideRestMinMs"`
	// RoadsideRestMaxMs is the maximum duration for a roadside rest period.
	RoadsideRestMaxMs int64 `json:"roadsideRestMaxMs"`
	// RoadsideRestHpPerS is the HP/MaxHP fraction healed per second during roadside rest.
	RoadsideRestHpPerS float64 `json:"roadsideRestHpPerSecond"`
	// AdventureRestHpPerS is the HP/MaxHP fraction healed per second during adventure inline rest.
	AdventureRestHpPerS float64 `json:"adventureRestHpPerSecond"`
}

func DefaultValues() Values {
	return Values{
		EncounterCooldownBaseMs: 12_000,
		EncounterActivityBase:   0.035,
		BaseMoveSpeed:           2.0,
		MovementTickRateMs:      500,
		PositionSyncRateMs:      10_000,
		TownRestMinMs:           5 * 60 * 1000,
		TownRestMaxMs:           20 * 60 * 1000,
		TownRestHPPerS:          0.002,
		TownArrivalRadius:       0.5,
		TownNPCVisitChance:      0.78,
		TownNPCRollMinMs:        800,
		TownNPCRollMaxMs:        2600,
		TownNPCRetryMs:          450,
		TownNPCPauseMs:          30_000,
		TownNPCLogIntervalMs:    5_000,
		WanderingMerchantPromptTimeoutMs: 15_000,
		MerchantCostBase:                 20,
		MerchantCostPerLevel:             5,
		MerchantTownAutoSellShare:        0.30,
		MonsterEncounterWeightBase:       0.62,
		MonsterEncounterWeightWildBonus:  0.18,
		MerchantEncounterWeightBase:      0.04,
		MerchantEncounterWeightRoadBonus: 0.10,
		LootChanceCommon:                 0.40,
		LootChanceUncommon:               0.10,
		LootChanceRare:                   0.02,
		LootChanceEpic:                   0.003,
		LootChanceLegendary:              0.0005,
		GoldLootScale:                    0.5,
		PotionDropChance:                 0.05,
		EquipmentDropBase:                0.15,
		GoldCommonMin:                    0,
		GoldCommonMax:                    5,
		GoldUncommonMin:                  6,
		GoldUncommonMax:                  20,
		GoldRareMin:                      21,
		GoldRareMax:                      50,
		GoldEpicMin:                      51,
		GoldEpicMax:                      120,
		GoldLegendaryMin:                 121,
		GoldLegendaryMax:                 300,
		AutoSellCommon:                   3,
		AutoSellUncommon:                 8,
		AutoSellRare:                     20,
		AutoSellEpic:                     60,
		AutoSellLegendary:                180,
		RESTEncounterCooldownMs:          16_000,
		RESTEncounterNPCChance:           0.10,
		NPCCostHeal:                      100,
		NPCCostPotion:                    50,
		NPCCostNearbyRadius:              3.0,
		CombatDamageScale:                0.35,
		EnemyDodgeChance:                 0.20,
		EnemyCriticalMinChance:           0.15,
		EnemyBurstEveryN:                 3,
		EnemyBurstMultiplier:             1.5,
		EnemyChainEveryN:                 6,
		EnemyChainMultiplier:             3.0,
		DebuffProcBurn:                   0.30,
		DebuffProcPoison:                 0.10,
		DebuffProcSlow:                   0.25,
		DebuffProcStun:                   0.25,
		DebuffProcFreeze:                 0.20,
		DebuffProcIceSlow:                0.20,
		EnemyRegenDefault:                0.02,
		EnemyRegenSkeletonKing:           0.10,
		EnemyRegenForestWarden:           0.05,
		EnemyRegenBattleLizard:           0.02,
		SummonCycleSeconds:               15,
		SummonDamageDivisor:              4,
		LuckBuffMultiplier:               1.75,
		MinAttackIntervalMs:              250,
		CombatPaceMultiplier:             5,
		PotionHealPercent:                0.30,
		PotionAutoUseThreshold:           0.30,
		ReviveHpPercent:                  0.50,
		AutoReviveAfterMs:                int64(time.Hour / time.Millisecond),
		XPCurveEarlyBase:                 180,
		XPCurveEarlyScale:                1.28,
		XPCurveMidBase:                   1450,
		XPCurveMidScale:                  1.15,
		XPCurveLateBase:                  23000,
		XPCurveLateScale:                 1.10,
		LevelUpHPEvery:                   10,
		LevelUpATKEvery:                  30,
		LevelUpDEFEvery:                  30,
		LevelUpSTREvery:                  40,
		LevelUpCONEvery:                  50,
		LevelUpAGIEvery:                  60,
		LevelUpLUCKEvery:                 100,
		AgilityCoef:                      0.03,
		MaxAttackSpeed:                   4.0,
		MinAttackSpeed:                   0.1,
		IlvlFactorSlope:                  0.03,
		RarityMultiplierCommon:           1.00,
		RarityMultiplierUncommon:         1.12,
		RarityMultiplierRare:             1.30,
		RarityMultiplierEpic:             1.52,
		RarityMultiplierLegendary:        1.78,
		RollIlvlEliteBaseChance:          0.4,
		RollIlvlElitePlusOneChance:       0.4,
		BuffChargePeriodMs:               24 * 60 * 60 * 1000,
		FreeBuffActivationsPerPeriod:     2,
		SubscriptionDurationMs:           7 * 24 * 60 * 60 * 1000,
		SubscriptionWeeklyPriceRUB:       299,
		BuffRefillPriceRUB:               50,
		ResurrectionRefillPriceRUB:       150,
		MaxRevivesFree:                   1,
		MaxRevivesSubscriber:             2,
		EnemyScaleBandHP:                 0.05,
		EnemyScaleOvercapHP:              0.025,
		EnemyScaleBandATK:                0.035,
		EnemyScaleOvercapATK:             0.018,
		EnemyScaleBandDEF:                0.035,
		EnemyScaleOvercapDEF:             0.018,
		EnemyScaleBandXP:                 0.05,
		EnemyScaleOvercapXP:              0.03,
		EnemyScaleBandGold:               0.05,
		EnemyScaleOvercapGold:            0.025,
		AutoEquipThreshold:               1.03,
		LootHistoryLimit:                 50,

		AdventureStartChance:             0.0001,
		AdventureCooldownMs:              300_000,
		AdventureOutDurationMs:           20_000,
		AdventureWildMinMs:               560_000,
		AdventureWildMaxMs:               2_960_000,
		AdventureReturnDurationMs:        20_000,
		AdventureDepthWorldUnits:         20.0,
		AdventureEncounterCooldownMs:     6_000,
		AdventureReturnEncounterEnabled:  true,

		LowHpThreshold:                   0.25,
		RoadsideRestExitHp:               0.70,
		AdventureRestTargetHp:            0.70,
		RoadsideRestMinMs:                240_000,
		RoadsideRestMaxMs:                600_000,
		RoadsideRestHpPerS:               0.003,
		AdventureRestHpPerS:              0.004,
	}
}

var current atomic.Value

func init() {
	v := DefaultValues()
	current.Store(&v)
}

func Get() Values {
	p := current.Load().(*Values)
	return *p
}

func Set(v Values) {
	current.Store(&v)
}

type PayloadLoader interface {
	LoadRuntimeConfigPayload(ctx context.Context) ([]byte, error)
}

func ReloadNow(ctx context.Context, logger *slog.Logger, loader PayloadLoader) error {
	payload, err := loader.LoadRuntimeConfigPayload(ctx)
	if err != nil {
		if logger != nil {
			logger.Warn("runtime config reload failed", "error", err)
		}
		return err
	}
	next := DefaultValues()
	if len(payload) > 0 {
		if err := json.Unmarshal(payload, &next); err != nil {
			if logger != nil {
				logger.Warn("runtime config payload parse failed", "error", err)
			}
			return err
		}
	}
	Set(next)
	return nil
}

