package achievements

import (
	"eq2emu/internal/database"
	"fmt"
	"time"
)

// LoadAllAchievements loads all achievements from database into master list
func LoadAllAchievements(db *database.DB, masterList *MasterList) error {
	query := `SELECT achievement_id, title, uncompleted_text, completed_text,
			  category, expansion, icon, point_value, qty_req, hide_achievement,
			  unknown3a, unknown3b FROM achievements`

	err := db.Query(query, func(row *database.Row) error {
		achievement := NewAchievement()
		achievement.ID = uint32(row.Int(0))
		achievement.Title = row.Text(1)
		achievement.UncompletedText = row.Text(2)
		achievement.CompletedText = row.Text(3)
		achievement.Category = row.Text(4)
		achievement.Expansion = row.Text(5)
		achievement.Icon = uint16(row.Int(6))
		achievement.PointValue = uint32(row.Int(7))
		achievement.QtyRequired = uint32(row.Int(8))
		achievement.Hide = row.Bool(9)
		achievement.Unknown3A = uint32(row.Int(10))
		achievement.Unknown3B = uint32(row.Int(11))

		// Load requirements and rewards
		if err := loadAchievementRequirements(db, achievement); err != nil {
			return fmt.Errorf("failed to load requirements for achievement %d: %w", achievement.ID, err)
		}

		if err := loadAchievementRewards(db, achievement); err != nil {
			return fmt.Errorf("failed to load rewards for achievement %d: %w", achievement.ID, err)
		}

		if !masterList.AddAchievement(achievement) {
			return fmt.Errorf("duplicate achievement ID: %d", achievement.ID)
		}

		return nil
	})

	return err
}

// loadAchievementRequirements loads requirements for a specific achievement
func loadAchievementRequirements(db *database.DB, achievement *Achievement) error {
	query := `SELECT achievement_id, name, qty_req
			  FROM achievements_requirements
			  WHERE achievement_id = ?`

	return db.Query(query, func(row *database.Row) error {
		req := Requirement{
			AchievementID: uint32(row.Int(0)),
			Name:          row.Text(1),
			QtyRequired:   uint32(row.Int(2)),
		}
		achievement.AddRequirement(req)
		return nil
	}, achievement.ID)
}

// loadAchievementRewards loads rewards for a specific achievement
func loadAchievementRewards(db *database.DB, achievement *Achievement) error {
	query := `SELECT achievement_id, reward
			  FROM achievements_rewards
			  WHERE achievement_id = ?`

	return db.Query(query, func(row *database.Row) error {
		reward := Reward{
			AchievementID: uint32(row.Int(0)),
			Reward:        row.Text(1),
		}
		achievement.AddReward(reward)
		return nil
	}, achievement.ID)
}

// LoadPlayerAchievements loads player achievements from database
func LoadPlayerAchievements(db *database.DB, playerID uint32, playerList *PlayerList) error {
	query := `SELECT achievement_id, title, uncompleted_text, completed_text,
			  category, expansion, icon, point_value, qty_req, hide_achievement,
			  unknown3a, unknown3b FROM achievements`

	err := db.Query(query, func(row *database.Row) error {
		achievement := NewAchievement()
		achievement.ID = uint32(row.Int(0))
		achievement.Title = row.Text(1)
		achievement.UncompletedText = row.Text(2)
		achievement.CompletedText = row.Text(3)
		achievement.Category = row.Text(4)
		achievement.Expansion = row.Text(5)
		achievement.Icon = uint16(row.Int(6))
		achievement.PointValue = uint32(row.Int(7))
		achievement.QtyRequired = uint32(row.Int(8))
		achievement.Hide = row.Bool(9)
		achievement.Unknown3A = uint32(row.Int(10))
		achievement.Unknown3B = uint32(row.Int(11))

		// Load requirements and rewards
		if err := loadAchievementRequirements(db, achievement); err != nil {
			return fmt.Errorf("failed to load requirements: %w", err)
		}

		if err := loadAchievementRewards(db, achievement); err != nil {
			return fmt.Errorf("failed to load rewards: %w", err)
		}

		if !playerList.AddAchievement(achievement) {
			return fmt.Errorf("duplicate achievement ID: %d", achievement.ID)
		}

		return nil
	})

	return err
}

// LoadPlayerAchievementUpdates loads player achievement progress from database
func LoadPlayerAchievementUpdates(db *database.DB, playerID uint32, updateList *PlayerUpdateList) error {
	query := `SELECT char_id, achievement_id, completed_date
			  FROM character_achievements
			  WHERE char_id = ?`

	return db.Query(query, func(row *database.Row) error {
		update := NewUpdate()
		update.ID = uint32(row.Int(1))

		// Convert completed_date from Unix timestamp
		if !row.IsNull(2) {
			timestamp := row.Int64(2)
			update.CompletedDate = time.Unix(timestamp, 0)
		}

		// Load update items
		if err := loadPlayerAchievementUpdateItems(db, playerID, update); err != nil {
			return fmt.Errorf("failed to load update items: %w", err)
		}

		if !updateList.AddUpdate(update) {
			return fmt.Errorf("duplicate achievement update ID: %d", update.ID)
		}

		return nil
	}, playerID)
}

// loadPlayerAchievementUpdateItems loads progress items for an achievement update
func loadPlayerAchievementUpdateItems(db *database.DB, playerID uint32, update *Update) error {
	query := `SELECT achievement_id, items
			  FROM character_achievements_items
			  WHERE char_id = ? AND achievement_id = ?`

	return db.Query(query, func(row *database.Row) error {
		item := UpdateItem{
			AchievementID: uint32(row.Int(0)),
			ItemUpdate:    uint32(row.Int(1)),
		}
		update.AddUpdateItem(item)
		return nil
	}, playerID, update.ID)
}

// SavePlayerAchievementUpdate saves or updates player achievement progress
func SavePlayerAchievementUpdate(db *database.DB, playerID uint32, update *Update) error {
	return db.Transaction(func(tx *database.DB) error {
		// Save or update main achievement record
		query := `INSERT OR REPLACE INTO character_achievements
				  (char_id, achievement_id, completed_date) VALUES (?, ?, ?)`

		var completedDate *int64
		if !update.CompletedDate.IsZero() {
			timestamp := update.CompletedDate.Unix()
			completedDate = &timestamp
		}

		if err := tx.Exec(query, playerID, update.ID, completedDate); err != nil {
			return fmt.Errorf("failed to save achievement update: %w", err)
		}

		// Delete existing update items
		deleteQuery := `DELETE FROM character_achievements_items
					   WHERE char_id = ? AND achievement_id = ?`
		if err := tx.Exec(deleteQuery, playerID, update.ID); err != nil {
			return fmt.Errorf("failed to delete old update items: %w", err)
		}

		// Insert new update items
		itemQuery := `INSERT INTO character_achievements_items
					  (char_id, achievement_id, items) VALUES (?, ?, ?)`
		for _, item := range update.UpdateItems {
			if err := tx.Exec(itemQuery, playerID, item.AchievementID, item.ItemUpdate); err != nil {
				return fmt.Errorf("failed to save update item: %w", err)
			}
		}

		return nil
	})
}

// DeletePlayerAchievementUpdate removes player achievement progress from database
func DeletePlayerAchievementUpdate(db *database.DB, playerID uint32, achievementID uint32) error {
	return db.Transaction(func(tx *database.DB) error {
		// Delete main achievement record
		query := `DELETE FROM character_achievements
				  WHERE char_id = ? AND achievement_id = ?`
		if err := tx.Exec(query, playerID, achievementID); err != nil {
			return fmt.Errorf("failed to delete achievement update: %w", err)
		}

		// Delete update items
		itemQuery := `DELETE FROM character_achievements_items
					  WHERE char_id = ? AND achievement_id = ?`
		if err := tx.Exec(itemQuery, playerID, achievementID); err != nil {
			return fmt.Errorf("failed to delete update items: %w", err)
		}

		return nil
	})
}

// SaveAchievement saves or updates an achievement in the database
func SaveAchievement(db *database.DB, achievement *Achievement) error {
	return db.Transaction(func(tx *database.DB) error {
		// Save main achievement record
		query := `INSERT OR REPLACE INTO achievements
				  (achievement_id, title, uncompleted_text, completed_text,
				   category, expansion, icon, point_value, qty_req,
				   hide_achievement, unknown3a, unknown3b)
				  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`

		if err := tx.Exec(query, achievement.ID, achievement.Title,
			achievement.UncompletedText, achievement.CompletedText,
			achievement.Category, achievement.Expansion, achievement.Icon,
			achievement.PointValue, achievement.QtyRequired, achievement.Hide,
			achievement.Unknown3A, achievement.Unknown3B); err != nil {
			return fmt.Errorf("failed to save achievement: %w", err)
		}

		// Delete existing requirements and rewards
		if err := tx.Exec("DELETE FROM achievements_requirements WHERE achievement_id = ?", achievement.ID); err != nil {
			return fmt.Errorf("failed to delete old requirements: %w", err)
		}
		if err := tx.Exec("DELETE FROM achievements_rewards WHERE achievement_id = ?", achievement.ID); err != nil {
			return fmt.Errorf("failed to delete old rewards: %w", err)
		}

		// Insert requirements
		reqQuery := `INSERT INTO achievements_requirements
					 (achievement_id, name, qty_req) VALUES (?, ?, ?)`
		for _, req := range achievement.Requirements {
			if err := tx.Exec(reqQuery, req.AchievementID, req.Name, req.QtyRequired); err != nil {
				return fmt.Errorf("failed to save requirement: %w", err)
			}
		}

		// Insert rewards
		rewardQuery := `INSERT INTO achievements_rewards
					   (achievement_id, reward) VALUES (?, ?)`
		for _, reward := range achievement.Rewards {
			if err := tx.Exec(rewardQuery, reward.AchievementID, reward.Reward); err != nil {
				return fmt.Errorf("failed to save reward: %w", err)
			}
		}

		return nil
	})
}

// DeleteAchievement removes an achievement and all related records from database
func DeleteAchievement(db *database.DB, achievementID uint32) error {
	return db.Transaction(func(tx *database.DB) error {
		// Delete main achievement
		if err := tx.Exec("DELETE FROM achievements WHERE achievement_id = ?", achievementID); err != nil {
			return fmt.Errorf("failed to delete achievement: %w", err)
		}

		// Delete requirements
		if err := tx.Exec("DELETE FROM achievements_requirements WHERE achievement_id = ?", achievementID); err != nil {
			return fmt.Errorf("failed to delete requirements: %w", err)
		}

		// Delete rewards
		if err := tx.Exec("DELETE FROM achievements_rewards WHERE achievement_id = ?", achievementID); err != nil {
			return fmt.Errorf("failed to delete rewards: %w", err)
		}

		// Delete player progress (optional - might want to preserve history)
		if err := tx.Exec("DELETE FROM character_achievements WHERE achievement_id = ?", achievementID); err != nil {
			return fmt.Errorf("failed to delete player achievements: %w", err)
		}
		if err := tx.Exec("DELETE FROM character_achievements_items WHERE achievement_id = ?", achievementID); err != nil {
			return fmt.Errorf("failed to delete player achievement items: %w", err)
		}

		return nil
	})
}
