package alt_advancement

import (
	"fmt"
	"time"
)

// LoadAltAdvancements loads all AA definitions from the database
func (db *DatabaseImpl) LoadAltAdvancements() error {
	query := `
		SELECT nodeid, minlevel, spellcrc, name, description, aa_list_fk, 
			   icon_id, icon_backdrop, xcoord, ycoord, pointspertier, maxtier, 
			   firstparentid, firstparentrequiredtier, displayedclassification,
			   requiredclassification, classificationpointsrequired, 
			   pointsspentintreetounlock, title, titlelevel 
		FROM spell_aa_nodelist 
		ORDER BY aa_list_fk, ycoord, xcoord`

	rows, err := db.db.Query(query)
	if err != nil {
		return fmt.Errorf("failed to query AA data: %v", err)
	}
	defer rows.Close()

	loadedCount := 0
	for rows.Next() {
		data := &AltAdvanceData{
			CreatedAt: time.Now(),
			UpdatedAt: time.Now(),
		}

		err := rows.Scan(
			&data.NodeID,
			&data.MinLevel,
			&data.SpellCRC,
			&data.Name,
			&data.Description,
			&data.Group,
			&data.Icon,
			&data.Icon2,
			&data.Col,
			&data.Row,
			&data.RankCost,
			&data.MaxRank,
			&data.RankPrereqID,
			&data.RankPrereq,
			&data.ClassReq,
			&data.Tier,
			&data.ReqPoints,
			&data.ReqTreePoints,
			&data.LineTitle,
			&data.TitleLevel,
		)
		if err != nil {
			return fmt.Errorf("failed to scan AA data: %v", err)
		}

		// Set spell ID to node ID if not provided separately
		data.SpellID = data.NodeID

		// Validate and add to master list
		if err := db.masterAAList.AddAltAdvancement(data); err != nil {
			// Log warning but continue loading
			if db.logger != nil {
				db.logger.Printf("Warning: failed to add AA node %d: %v", data.NodeID, err)
			}
			continue
		}

		loadedCount++
	}

	if err = rows.Err(); err != nil {
		return fmt.Errorf("error iterating AA rows: %v", err)
	}

	// Sort AAs within each group for proper display order
	db.masterAAList.SortAAsByGroup()

	if db.logger != nil {
		db.logger.Printf("Loaded %d Alternate Advancement(s)", loadedCount)
	}

	return nil
}

// LoadTreeNodes loads tree node configurations from the database
func (db *DatabaseImpl) LoadTreeNodes() error {
	query := `
		SELECT class_id, tree_node, aa_tree_id 
		FROM spell_aa_class_list 
		ORDER BY class_id, tree_node`

	rows, err := db.db.Query(query)
	if err != nil {
		return fmt.Errorf("failed to query tree node data: %v", err)
	}
	defer rows.Close()

	loadedCount := 0
	for rows.Next() {
		data := &TreeNodeData{}

		err := rows.Scan(
			&data.ClassID,
			&data.TreeID,
			&data.AATreeID,
		)
		if err != nil {
			return fmt.Errorf("failed to scan tree node data: %v", err)
		}

		// Add to master node list
		if err := db.masterNodeList.AddTreeNode(data); err != nil {
			// Log warning but continue loading
			if db.logger != nil {
				db.logger.Printf("Warning: failed to add tree node %d: %v", data.TreeID, err)
			}
			continue
		}

		loadedCount++
	}

	if err = rows.Err(); err != nil {
		return fmt.Errorf("error iterating tree node rows: %v", err)
	}

	if db.logger != nil {
		db.logger.Printf("Loaded %d AA Tree Nodes", loadedCount)
	}

	return nil
}

// LoadPlayerAA loads AA data for a specific player
func (db *DatabaseImpl) LoadPlayerAA(characterID int32) (*AAPlayerState, error) {
	playerState := NewAAPlayerState(characterID)

	// Load player's AA entries
	query := `
		SELECT template_id, tab_id, aa_id, order, treeid 
		FROM character_aa 
		WHERE char_id = ? 
		ORDER BY template_id, tab_id, order`

	rows, err := db.db.Query(query, characterID)
	if err != nil {
		return nil, fmt.Errorf("failed to query player AA data: %v", err)
	}
	defer rows.Close()

	// Group entries by template
	templateEntries := make(map[int8][]*AAEntry)

	for rows.Next() {
		entry := &AAEntry{}

		err := rows.Scan(
			&entry.TemplateID,
			&entry.TabID,
			&entry.AAID,
			&entry.Order,
			&entry.TreeID,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan player AA entry: %v", err)
		}

		if templateEntries[entry.TemplateID] == nil {
			templateEntries[entry.TemplateID] = make([]*AAEntry, 0)
		}
		templateEntries[entry.TemplateID] = append(templateEntries[entry.TemplateID], entry)
	}

	if err = rows.Err(); err != nil {
		return nil, fmt.Errorf("error iterating player AA rows: %v", err)
	}

	// Create templates from loaded entries
	for templateID, entries := range templateEntries {
		template := NewAATemplate(templateID, GetTemplateName(templateID))
		template.Entries = entries
		playerState.Templates[templateID] = template
	}

	// Load player's AA progression data
	err = db.loadPlayerAAProgress(characterID, playerState)
	if err != nil {
		return nil, fmt.Errorf("failed to load player AA progress: %v", err)
	}

	// Load player's AA point totals
	err = db.loadPlayerAAPoints(characterID, playerState)
	if err != nil {
		return nil, fmt.Errorf("failed to load player AA points: %v", err)
	}

	// Initialize tabs based on loaded data
	db.initializePlayerTabs(playerState)

	return playerState, nil
}

// loadPlayerAAProgress loads detailed AA progression for a player
func (db *DatabaseImpl) loadPlayerAAProgress(characterID int32, playerState *AAPlayerState) error {
	query := `
		SELECT node_id, current_rank, points_spent, template_id, tab_id, 
			   purchased_at, updated_at 
		FROM character_aa_progress 
		WHERE character_id = ?`

	rows, err := db.db.Query(query, characterID)
	if err != nil {
		return fmt.Errorf("failed to query player AA progress: %v", err)
	}
	defer rows.Close()

	for rows.Next() {
		progress := &PlayerAAData{
			CharacterID: characterID,
		}

		var purchasedAt, updatedAt string
		err := rows.Scan(
			&progress.NodeID,
			&progress.CurrentRank,
			&progress.PointsSpent,
			&progress.TemplateID,
			&progress.TabID,
			&purchasedAt,
			&updatedAt,
		)
		if err != nil {
			return fmt.Errorf("failed to scan player AA progress: %v", err)
		}

		// Parse timestamps
		if progress.PurchasedAt, err = time.Parse("2006-01-02 15:04:05", purchasedAt); err != nil {
			progress.PurchasedAt = time.Now()
		}
		if progress.UpdatedAt, err = time.Parse("2006-01-02 15:04:05", updatedAt); err != nil {
			progress.UpdatedAt = time.Now()
		}

		playerState.AAProgress[progress.NodeID] = progress
	}

	return rows.Err()
}

// loadPlayerAAPoints loads AA point totals for a player
func (db *DatabaseImpl) loadPlayerAAPoints(characterID int32, playerState *AAPlayerState) error {
	query := `
		SELECT total_points, spent_points, available_points, banked_points,
			   active_template 
		FROM character_aa_points 
		WHERE character_id = ?`

	row := db.db.QueryRow(query, characterID)

	err := row.Scan(
		&playerState.TotalPoints,
		&playerState.SpentPoints,
		&playerState.AvailablePoints,
		&playerState.BankedPoints,
		&playerState.ActiveTemplate,
	)

	if err != nil {
		// If no record exists, initialize with defaults
		if err.Error() == "sql: no rows in result set" {
			playerState.TotalPoints = 0
			playerState.SpentPoints = 0
			playerState.AvailablePoints = 0
			playerState.BankedPoints = 0
			playerState.ActiveTemplate = AA_TEMPLATE_CURRENT
			return nil
		}
		return fmt.Errorf("failed to load player AA points: %v", err)
	}

	return nil
}

// initializePlayerTabs initializes tab states based on loaded data
func (db *DatabaseImpl) initializePlayerTabs(playerState *AAPlayerState) {
	// Initialize all standard tabs
	for i := int8(0); i < 10; i++ {
		tab := NewAATab(i, i, GetTabName(i))
		tab.MaxAA = GetMaxAAForTab(i)

		// Calculate points spent in this tab
		pointsSpent := int32(0)
		for _, progress := range playerState.AAProgress {
			if progress.TabID == i {
				pointsSpent += progress.PointsSpent
			}
		}
		tab.PointsSpent = pointsSpent
		tab.PointsAvailable = playerState.AvailablePoints

		playerState.Tabs[i] = tab
	}
}

// SavePlayerAA saves a player's AA data to the database
func (db *DatabaseImpl) SavePlayerAA(playerState *AAPlayerState) error {
	if playerState == nil {
		return fmt.Errorf("player state cannot be nil")
	}

	// Start transaction
	tx, err := db.db.Begin()
	if err != nil {
		return fmt.Errorf("failed to begin transaction: %v", err)
	}
	defer tx.Rollback()

	// Save AA point totals
	err = db.savePlayerAAPoints(tx, playerState)
	if err != nil {
		return fmt.Errorf("failed to save player AA points: %v", err)
	}

	// Save AA progress
	err = db.savePlayerAAProgress(tx, playerState)
	if err != nil {
		return fmt.Errorf("failed to save player AA progress: %v", err)
	}

	// Save template entries
	err = db.savePlayerAATemplates(tx, playerState)
	if err != nil {
		return fmt.Errorf("failed to save player AA templates: %v", err)
	}

	// Commit transaction
	if err = tx.Commit(); err != nil {
		return fmt.Errorf("failed to commit transaction: %v", err)
	}

	// Update last save time
	playerState.lastUpdate = time.Now()
	playerState.needsSync = false

	return nil
}

// savePlayerAAPoints saves AA point totals to the database
func (db *DatabaseImpl) savePlayerAAPoints(tx Transaction, playerState *AAPlayerState) error {
	query := `
		INSERT OR REPLACE INTO character_aa_points 
		(character_id, total_points, spent_points, available_points, 
		 banked_points, active_template, updated_at) 
		VALUES (?, ?, ?, ?, ?, ?, ?)`

	_, err := tx.Exec(query,
		playerState.CharacterID,
		playerState.TotalPoints,
		playerState.SpentPoints,
		playerState.AvailablePoints,
		playerState.BankedPoints,
		playerState.ActiveTemplate,
		time.Now().Format("2006-01-02 15:04:05"),
	)

	return err
}

// savePlayerAAProgress saves AA progression data to the database
func (db *DatabaseImpl) savePlayerAAProgress(tx Transaction, playerState *AAPlayerState) error {
	// Delete existing progress
	_, err := tx.Exec("DELETE FROM character_aa_progress WHERE character_id = ?", playerState.CharacterID)
	if err != nil {
		return err
	}

	// Insert current progress
	query := `
		INSERT INTO character_aa_progress 
		(character_id, node_id, current_rank, points_spent, template_id, 
		 tab_id, purchased_at, updated_at) 
		VALUES (?, ?, ?, ?, ?, ?, ?, ?)`

	for _, progress := range playerState.AAProgress {
		_, err = tx.Exec(query,
			progress.CharacterID,
			progress.NodeID,
			progress.CurrentRank,
			progress.PointsSpent,
			progress.TemplateID,
			progress.TabID,
			progress.PurchasedAt.Format("2006-01-02 15:04:05"),
			progress.UpdatedAt.Format("2006-01-02 15:04:05"),
		)
		if err != nil {
			return err
		}
	}

	return nil
}

// savePlayerAATemplates saves AA template entries to the database
func (db *DatabaseImpl) savePlayerAATemplates(tx Transaction, playerState *AAPlayerState) error {
	// Delete existing entries for server templates (4-6)
	_, err := tx.Exec("DELETE FROM character_aa WHERE char_id = ? AND template_id BETWEEN 4 AND 6", playerState.CharacterID)
	if err != nil {
		return err
	}

	// Insert current template entries for server templates only
	query := `
		INSERT INTO character_aa 
		(char_id, template_id, tab_id, aa_id, order, treeid) 
		VALUES (?, ?, ?, ?, ?, ?)`

	for _, template := range playerState.Templates {
		// Only save server templates (4-6) as personal templates (1-3) are class defaults
		if template.TemplateID >= 4 && template.TemplateID <= 6 {
			for _, entry := range template.Entries {
				_, err = tx.Exec(query,
					playerState.CharacterID,
					entry.TemplateID,
					entry.TabID,
					entry.AAID,
					entry.Order,
					entry.TreeID,
				)
				if err != nil {
					return err
				}
			}
		}
	}

	return nil
}

// LoadPlayerAADefaults loads default AA templates for a class
func (db *DatabaseImpl) LoadPlayerAADefaults(classID int8) (map[int8][]*AAEntry, error) {
	query := `
		SELECT template_id, tab_id, aa_id, order, treeid 
		FROM character_aa_defaults 
		WHERE class = ? 
		ORDER BY template_id, tab_id, order`

	rows, err := db.db.Query(query, classID)
	if err != nil {
		return nil, fmt.Errorf("failed to query AA defaults: %v", err)
	}
	defer rows.Close()

	templates := make(map[int8][]*AAEntry)

	for rows.Next() {
		entry := &AAEntry{}

		err := rows.Scan(
			&entry.TemplateID,
			&entry.TabID,
			&entry.AAID,
			&entry.Order,
			&entry.TreeID,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan AA default entry: %v", err)
		}

		if templates[entry.TemplateID] == nil {
			templates[entry.TemplateID] = make([]*AAEntry, 0)
		}
		templates[entry.TemplateID] = append(templates[entry.TemplateID], entry)
	}

	if err = rows.Err(); err != nil {
		return nil, fmt.Errorf("error iterating AA default rows: %v", err)
	}

	return templates, nil
}

// DeletePlayerAA removes all AA data for a player
func (db *DatabaseImpl) DeletePlayerAA(characterID int32) error {
	// Start transaction
	tx, err := db.db.Begin()
	if err != nil {
		return fmt.Errorf("failed to begin transaction: %v", err)
	}
	defer tx.Rollback()

	// Delete from all related tables
	tables := []string{
		"character_aa_points",
		"character_aa_progress",
		"character_aa",
	}

	for _, table := range tables {
		query := fmt.Sprintf("DELETE FROM %s WHERE char_id = ? OR character_id = ?", table)
		_, err = tx.Exec(query, characterID, characterID)
		if err != nil {
			return fmt.Errorf("failed to delete from %s: %v", table, err)
		}
	}

	// Commit transaction
	if err = tx.Commit(); err != nil {
		return fmt.Errorf("failed to commit transaction: %v", err)
	}

	return nil
}

// GetAAStatistics returns statistics about AA usage
func (db *DatabaseImpl) GetAAStatistics() (map[string]interface{}, error) {
	stats := make(map[string]interface{})

	// Get total players with AA data
	var totalPlayers int64
	err := db.db.QueryRow("SELECT COUNT(DISTINCT character_id) FROM character_aa_points").Scan(&totalPlayers)
	if err != nil {
		return nil, fmt.Errorf("failed to get total players: %v", err)
	}
	stats["total_players_with_aa"] = totalPlayers

	// Get average points spent
	var avgPointsSpent float64
	err = db.db.QueryRow("SELECT AVG(spent_points) FROM character_aa_points").Scan(&avgPointsSpent)
	if err != nil {
		return nil, fmt.Errorf("failed to get average points spent: %v", err)
	}
	stats["average_points_spent"] = avgPointsSpent

	// Get most popular AAs
	query := `
		SELECT node_id, COUNT(*) as usage_count 
		FROM character_aa_progress 
		WHERE current_rank > 0 
		GROUP BY node_id 
		ORDER BY usage_count DESC 
		LIMIT 10`

	rows, err := db.db.Query(query)
	if err != nil {
		return nil, fmt.Errorf("failed to query popular AAs: %v", err)
	}
	defer rows.Close()

	popularAAs := make(map[int32]int64)
	for rows.Next() {
		var nodeID int32
		var count int64
		err := rows.Scan(&nodeID, &count)
		if err != nil {
			return nil, fmt.Errorf("failed to scan popular AA: %v", err)
		}
		popularAAs[nodeID] = count
	}
	stats["popular_aas"] = popularAAs

	return stats, nil
}
