package player

import (
	"eq2emu/internal/entity"
	"time"
)

// GetXPVitality returns the player's adventure XP vitality
func (p *Player) GetXPVitality() float32 {
	return p.GetInfoStruct().GetXPVitality()
}

// GetTSXPVitality returns the player's tradeskill XP vitality
func (p *Player) GetTSXPVitality() float32 {
	return p.GetInfoStruct().GetTSXPVitality()
}

// AdventureXPEnabled returns whether adventure XP is enabled
func (p *Player) AdventureXPEnabled() bool {
	return p.GetInfoStruct().GetXPDebt() < 95.0 && p.GetCharacterFlag(CF_COMBAT_EXPERIENCE_ENABLED)
}

// TradeskillXPEnabled returns whether tradeskill XP is enabled
func (p *Player) TradeskillXPEnabled() bool {
	return p.GetInfoStruct().GetTSXPDebt() < 95.0 && p.GetCharacterFlag(CF_QUEST_EXPERIENCE_ENABLED)
}

// SetNeededXP sets the needed XP to a specific value
func (p *Player) SetNeededXP(val int32) {
	p.GetInfoStruct().SetXPNeeded(val)
}

// SetNeededXP sets the needed XP based on current level
func (p *Player) SetNeededXPByLevel() {
	p.GetInfoStruct().SetXPNeeded(GetNeededXPByLevel(p.GetLevel()))
}

// SetXP sets the current XP
func (p *Player) SetXP(val int32) {
	p.GetInfoStruct().SetXP(val)
}

// SetNeededTSXP sets the needed tradeskill XP to a specific value
func (p *Player) SetNeededTSXP(val int32) {
	p.GetInfoStruct().SetTSXPNeeded(val)
}

// SetNeededTSXPByLevel sets the needed tradeskill XP based on current level
func (p *Player) SetNeededTSXPByLevel() {
	p.GetInfoStruct().SetTSXPNeeded(GetNeededXPByLevel(p.GetTSLevel()))
}

// SetTSXP sets the current tradeskill XP
func (p *Player) SetTSXP(val int32) {
	p.GetInfoStruct().SetTSXP(val)
}

// GetNeededXP returns the XP needed for next level
func (p *Player) GetNeededXP() int32 {
	return p.GetInfoStruct().GetXPNeeded()
}

// GetXPDebt returns the current XP debt percentage
func (p *Player) GetXPDebt() float32 {
	return p.GetInfoStruct().GetXPDebt()
}

// GetXP returns the current XP
func (p *Player) GetXP() int32 {
	return p.GetInfoStruct().GetXP()
}

// GetNeededTSXP returns the tradeskill XP needed for next level
func (p *Player) GetNeededTSXP() int32 {
	return p.GetInfoStruct().GetTSXPNeeded()
}

// GetTSXP returns the current tradeskill XP
func (p *Player) GetTSXP() int32 {
	return p.GetInfoStruct().GetTSXP()
}

// AddXP adds adventure XP to the player
func (p *Player) AddXP(xpAmount int32) bool {
	if xpAmount <= 0 {
		return false
	}

	info := p.GetInfoStruct()
	currentXP := info.GetXP()
	neededXP := info.GetXPNeeded()
	totalXP := currentXP + xpAmount

	// Check if we've reached next level
	if totalXP >= neededXP {
		// Level up!
		if p.GetLevel() < 100 { // Assuming max level is 100
			// Calculate overflow XP
			overflow := totalXP - neededXP

			// Level up
			p.SetLevel(p.GetLevel()+1, true)
			p.SetNeededXPByLevel()

			// Set XP to overflow amount
			p.SetXP(overflow)

			// TODO: Send level up packet/message
			// TODO: Update stats for new level
			// TODO: Check for new abilities/spells

			return true
		} else {
			// At max level, just set to max
			p.SetXP(neededXP - 1)
		}
	} else {
		p.SetXP(totalXP)
	}

	// TODO: Send XP update packet
	p.SetCharSheetChanged(true)
	return true
}

// AddTSXP adds tradeskill XP to the player
func (p *Player) AddTSXP(xpAmount int32) bool {
	if xpAmount <= 0 {
		return false
	}

	info := p.GetInfoStruct()
	currentXP := info.GetTSXP()
	neededXP := info.GetTSXPNeeded()
	totalXP := currentXP + xpAmount

	// Check if we've reached next level
	if totalXP >= neededXP {
		// Level up!
		if p.GetTSLevel() < 100 { // Assuming max TS level is 100
			// Calculate overflow XP
			overflow := totalXP - neededXP

			// Level up
			p.SetTSLevel(p.GetTSLevel() + 1)
			p.SetNeededTSXPByLevel()

			// Set XP to overflow amount
			p.SetTSXP(overflow)

			// TODO: Send level up packet/message
			// TODO: Update stats for new level
			// TODO: Check for new recipes

			return true
		} else {
			// At max level, just set to max
			p.SetTSXP(neededXP - 1)
		}
	} else {
		p.SetTSXP(totalXP)
	}

	// TODO: Send XP update packet
	p.SetCharSheetChanged(true)
	return true
}

// DoubleXPEnabled returns whether double XP is enabled
func (p *Player) DoubleXPEnabled() bool {
	// TODO: Check for double XP events, potions, etc.
	return false
}

// CalculateXP calculates the XP reward from a victim
func (p *Player) CalculateXP(victim *entity.Spawn) float32 {
	if victim == nil {
		return 0
	}

	// TODO: Implement full XP calculation formula
	// This is a simplified version

	victimLevel := victim.GetLevel()
	playerLevel := p.GetLevel()
	levelDiff := int(victimLevel) - int(playerLevel)

	// Base XP value
	baseXP := float32(100 + (victimLevel * 10))

	// Level difference modifier
	var levelMod float32 = 1.0
	if levelDiff < -5 {
		// Grey con, minimal XP
		levelMod = 0.1
	} else if levelDiff < -2 {
		// Green con, reduced XP
		levelMod = 0.5
	} else if levelDiff <= 2 {
		// Blue/White con, normal XP
		levelMod = 1.0
	} else if levelDiff <= 4 {
		// Yellow con, bonus XP
		levelMod = 1.2
	} else {
		// Orange/Red con, high bonus XP
		levelMod = 1.5
	}

	// Group modifier
	groupMod := float32(1.0)
	if p.group != nil {
		// TODO: Calculate group bonus
		groupMod = 0.8 // Simplified group penalty
	}

	// Vitality modifier
	vitalityMod := float32(1.0)
	if p.GetXPVitality() > 0 {
		vitalityMod = 2.0 // Double XP with vitality
	}

	// Double XP modifier
	doubleXPMod := float32(1.0)
	if p.DoubleXPEnabled() {
		doubleXPMod = 2.0
	}

	totalXP := baseXP * levelMod * groupMod * vitalityMod * doubleXPMod
	return totalXP
}

// CalculateTSXP calculates tradeskill XP for a given level
func (p *Player) CalculateTSXP(level int8) float32 {
	// TODO: Implement tradeskill XP calculation
	// This is a simplified version

	levelDiff := int(level) - int(p.GetTSLevel())
	baseXP := float32(50 + (level * 5))

	// Level difference modifier
	var levelMod float32 = 1.0
	if levelDiff < -5 {
		levelMod = 0.1
	} else if levelDiff < -2 {
		levelMod = 0.5
	} else if levelDiff <= 2 {
		levelMod = 1.0
	} else if levelDiff <= 4 {
		levelMod = 1.2
	} else {
		levelMod = 1.5
	}

	// Vitality modifier
	vitalityMod := float32(1.0)
	if p.GetTSXPVitality() > 0 {
		vitalityMod = 2.0
	}

	return baseXP * levelMod * vitalityMod
}

// CalculateOfflineDebtRecovery calculates debt recovery while offline
func (p *Player) CalculateOfflineDebtRecovery(unixTimestamp int32) {
	currentTime := int32(time.Now().Unix())
	timeDiff := currentTime - unixTimestamp

	if timeDiff <= 0 {
		return
	}

	// Calculate hours offline
	hoursOffline := float32(timeDiff) / 3600.0

	// Debt recovery rate per hour (example: 1% per hour)
	debtRecoveryRate := float32(1.0)

	// Calculate adventure debt recovery
	currentDebt := p.GetInfoStruct().GetXPDebt()
	if currentDebt > 0 {
		recovery := debtRecoveryRate * hoursOffline
		newDebt := currentDebt - recovery
		if newDebt < 0 {
			newDebt = 0
		}
		p.GetInfoStruct().SetXPDebt(newDebt)
	}

	// Calculate tradeskill debt recovery
	currentTSDebt := p.GetInfoStruct().GetTSXPDebt()
	if currentTSDebt > 0 {
		recovery := debtRecoveryRate * hoursOffline
		newDebt := currentTSDebt - recovery
		if newDebt < 0 {
			newDebt = 0
		}
		p.GetInfoStruct().SetTSXPDebt(newDebt)
	}
}

// GetTSLevel returns the player's tradeskill level
func (p *Player) GetTSLevel() int8 {
	return p.GetInfoStruct().GetTSLevel()
}

// SetTSLevel sets the player's tradeskill level
func (p *Player) SetTSLevel(level int8) {
	p.GetInfoStruct().SetTSLevel(level)
	p.SetCharSheetChanged(true)
}
