package titles

import (
	"sync"
	"time"
)

// Title represents a single character title with all its properties
type Title struct {
	ID          int32  `json:"id"`          // Unique title identifier
	Name        string `json:"name"`        // Display name of the title
	Description string `json:"description"` // Description shown in UI

	// Positioning and display
	Position      int32  `json:"position"`       // TitlePositionPrefix or TitlePositionSuffix
	DisplayFormat int32  `json:"display_format"` // How the title is formatted
	Color         uint32 `json:"color"`          // Color code for display

	// Classification
	Source   int32  `json:"source"`   // How the title is obtained (TitleSource*)
	Category string `json:"category"` // Category for organization
	Rarity   int32  `json:"rarity"`   // Title rarity level

	// Requirements and restrictions
	Requirements []TitleRequirement `json:"requirements"` // What's needed to unlock
	Flags        uint32             `json:"flags"`        // Various title flags

	// Metadata
	CreatedDate   time.Time `json:"created_date"`   // When title was added
	LastModified  time.Time `json:"last_modified"`  // When title was last updated
	MinLevel      int32     `json:"min_level"`      // Minimum character level
	MaxLevel      int32     `json:"max_level"`      // Maximum character level (0 = no limit)
	ExpansionID   int32     `json:"expansion_id"`   // Required expansion
	AchievementID uint32    `json:"achievement_id"` // Associated achievement if any

	// Expiration (for temporary titles)
	ExpirationHours int32 `json:"expiration_hours"` // Hours until expiration (0 = permanent)

	mutex sync.RWMutex // Thread safety
}

// TitleRequirement represents a single requirement for unlocking a title
type TitleRequirement struct {
	Type        int32  `json:"type"`         // RequirementType* constant
	Value       int32  `json:"value"`        // Required value/amount
	StringValue string `json:"string_value"` // For string-based requirements
	Description string `json:"description"`  // Human-readable requirement description
}

// PlayerTitle represents a title owned by a player
type PlayerTitle struct {
	TitleID    int32     `json:"title_id"`    // Reference to Title.ID
	PlayerID   int32     `json:"player_id"`   // Character ID who owns it
	EarnedDate time.Time `json:"earned_date"` // When the title was earned
	ExpiresAt  time.Time `json:"expires_at"`  // When temporary title expires (zero for permanent)
	IsActive   bool      `json:"is_active"`   // Whether title is currently displayed
	IsPrefix   bool      `json:"is_prefix"`   // True if used as prefix, false for suffix

	// Achievement context
	AchievementID uint32 `json:"achievement_id"` // Achievement that granted this title
	QuestID       uint32 `json:"quest_id"`       // Quest that granted this title

	mutex sync.RWMutex // Thread safety
}

// NewTitle creates a new title with default values
func NewTitle(id int32, name string) *Title {
	return &Title{
		ID:              id,
		Name:            name,
		Position:        TitlePositionSuffix,
		DisplayFormat:   DisplayFormatSimple,
		Color:           ColorCommon,
		Source:          TitleSourceMiscellaneous,
		Category:        CategoryMiscellaneous,
		Rarity:          TitleRarityCommon,
		Requirements:    make([]TitleRequirement, 0),
		Flags:           0,
		CreatedDate:     time.Now(),
		LastModified:    time.Now(),
		MinLevel:        1,
		MaxLevel:        0, // No limit
		ExpansionID:     0, // Base game
		AchievementID:   0,
		ExpirationHours: 0, // Permanent
	}
}

// NewPlayerTitle creates a new player title entry
func NewPlayerTitle(titleID, playerID int32) *PlayerTitle {
	return &PlayerTitle{
		TitleID:       titleID,
		PlayerID:      playerID,
		EarnedDate:    time.Now(),
		ExpiresAt:     time.Time{}, // Zero value = permanent
		IsActive:      false,
		IsPrefix:      false,
		AchievementID: 0,
		QuestID:       0,
	}
}

// IsExpired checks if a temporary title has expired
func (pt *PlayerTitle) IsExpired() bool {
	pt.mutex.RLock()
	defer pt.mutex.RUnlock()

	if pt.ExpiresAt.IsZero() {
		return false // Permanent title
	}
	return time.Now().After(pt.ExpiresAt)
}

// SetExpiration sets when a temporary title expires
func (pt *PlayerTitle) SetExpiration(hours int32) {
	pt.mutex.Lock()
	defer pt.mutex.Unlock()

	if hours <= 0 {
		pt.ExpiresAt = time.Time{} // Make permanent
	} else {
		pt.ExpiresAt = time.Now().Add(time.Duration(hours) * time.Hour)
	}
}

// Activate makes this title the active one for the player
func (pt *PlayerTitle) Activate(isPrefix bool) {
	pt.mutex.Lock()
	defer pt.mutex.Unlock()

	pt.IsActive = true
	pt.IsPrefix = isPrefix
}

// Deactivate removes this title from active display
func (pt *PlayerTitle) Deactivate() {
	pt.mutex.Lock()
	defer pt.mutex.Unlock()

	pt.IsActive = false
}

// Clone creates a deep copy of the title
func (t *Title) Clone() *Title {
	t.mutex.RLock()
	defer t.mutex.RUnlock()

	clone := &Title{
		ID:              t.ID,
		Name:            t.Name,
		Description:     t.Description,
		Position:        t.Position,
		DisplayFormat:   t.DisplayFormat,
		Color:           t.Color,
		Source:          t.Source,
		Category:        t.Category,
		Rarity:          t.Rarity,
		Requirements:    make([]TitleRequirement, len(t.Requirements)),
		Flags:           t.Flags,
		CreatedDate:     t.CreatedDate,
		LastModified:    t.LastModified,
		MinLevel:        t.MinLevel,
		MaxLevel:        t.MaxLevel,
		ExpansionID:     t.ExpansionID,
		AchievementID:   t.AchievementID,
		ExpirationHours: t.ExpirationHours,
	}

	copy(clone.Requirements, t.Requirements)
	return clone
}

// Clone creates a deep copy of the player title
func (pt *PlayerTitle) Clone() *PlayerTitle {
	pt.mutex.RLock()
	defer pt.mutex.RUnlock()

	return &PlayerTitle{
		TitleID:       pt.TitleID,
		PlayerID:      pt.PlayerID,
		EarnedDate:    pt.EarnedDate,
		ExpiresAt:     pt.ExpiresAt,
		IsActive:      pt.IsActive,
		IsPrefix:      pt.IsPrefix,
		AchievementID: pt.AchievementID,
		QuestID:       pt.QuestID,
	}
}

// HasFlag checks if the title has a specific flag set
func (t *Title) HasFlag(flag uint32) bool {
	t.mutex.RLock()
	defer t.mutex.RUnlock()

	return (t.Flags & flag) != 0
}

// SetFlag sets a specific flag on the title
func (t *Title) SetFlag(flag uint32) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.Flags |= flag
	t.LastModified = time.Now()
}

// ClearFlag removes a specific flag from the title
func (t *Title) ClearFlag(flag uint32) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.Flags &^= flag
	t.LastModified = time.Now()
}

// AddRequirement adds a new requirement to the title
func (t *Title) AddRequirement(reqType int32, value int32, stringValue, description string) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	req := TitleRequirement{
		Type:        reqType,
		Value:       value,
		StringValue: stringValue,
		Description: description,
	}

	t.Requirements = append(t.Requirements, req)
	t.LastModified = time.Now()
}

// ClearRequirements removes all requirements from the title
func (t *Title) ClearRequirements() {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.Requirements = make([]TitleRequirement, 0)
	t.LastModified = time.Now()
}

// IsHidden checks if the title is hidden from normal display
func (t *Title) IsHidden() bool {
	return t.HasFlag(FlagHidden)
}

// IsAccountWide checks if the title is available to all characters on the account
func (t *Title) IsAccountWide() bool {
	return t.HasFlag(FlagAccountWide)
}

// IsUnique checks if only one player can have this title
func (t *Title) IsUnique() bool {
	return t.HasFlag(FlagUnique)
}

// IsTemporary checks if the title expires after a certain time
func (t *Title) IsTemporary() bool {
	return t.HasFlag(FlagTemporary)
}

// IsGMOnly checks if the title is restricted to Game Masters
func (t *Title) IsGMOnly() bool {
	return t.HasFlag(FlagGMOnly)
}

// GetDisplayName returns the formatted title name for display
func (t *Title) GetDisplayName() string {
	t.mutex.RLock()
	defer t.mutex.RUnlock()

	switch t.DisplayFormat {
	case DisplayFormatWithBrackets:
		return "[" + t.Name + "]"
	case DisplayFormatWithQuotes:
		return "\"" + t.Name + "\""
	case DisplayFormatWithCommas:
		return "," + t.Name + ","
	default:
		return t.Name
	}
}

// SetDescription updates the title description
func (t *Title) SetDescription(description string) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.Description = description
	t.LastModified = time.Now()
}

// SetCategory updates the title category
func (t *Title) SetCategory(category string) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.Category = category
	t.LastModified = time.Now()
}

// SetRarity updates the title rarity and adjusts color accordingly
func (t *Title) SetRarity(rarity int32) {
	t.mutex.Lock()
	defer t.mutex.Unlock()

	t.Rarity = rarity

	// Update color based on rarity
	switch rarity {
	case TitleRarityCommon:
		t.Color = ColorCommon
	case TitleRarityUncommon:
		t.Color = ColorUncommon
	case TitleRarityRare:
		t.Color = ColorRare
	case TitleRarityEpic:
		t.Color = ColorEpic
	case TitleRarityLegendary:
		t.Color = ColorLegendary
	case TitleRarityUnique:
		t.Color = ColorUnique
	}

	t.LastModified = time.Now()
}
