package ground_spawn

import (
	"fmt"

	"eq2emu/internal/database"
)

// DatabaseAdapter implements the Database interface using the internal database wrapper
type DatabaseAdapter struct {
	db *database.DB
}

// NewDatabaseAdapter creates a new database adapter using the database wrapper
func NewDatabaseAdapter(db *database.DB) *DatabaseAdapter {
	return &DatabaseAdapter{
		db: db,
	}
}

// LoadGroundSpawnEntries loads harvest entries for a ground spawn
func (da *DatabaseAdapter) LoadGroundSpawnEntries(groundspawnID int32) ([]*GroundSpawnEntry, error) {
	query := `
		SELECT min_skill_level, min_adventure_level, bonus_table, harvest_1, harvest_3, 
		       harvest_5, harvest_imbue, harvest_rare, harvest_10, harvest_coin
		FROM groundspawn_entries
		WHERE groundspawn_id = ?
		ORDER BY min_skill_level ASC
	`

	var entries []*GroundSpawnEntry

	err := da.db.Query(query, func(row *database.Row) error {
		entry := &GroundSpawnEntry{}
		var bonusTable int32

		entry.MinSkillLevel = int16(row.Int(0))
		entry.MinAdventureLevel = int16(row.Int(1))
		bonusTable = int32(row.Int(2))
		entry.Harvest1 = float32(row.Float(3))
		entry.Harvest3 = float32(row.Float(4))
		entry.Harvest5 = float32(row.Float(5))
		entry.HarvestImbue = float32(row.Float(6))
		entry.HarvestRare = float32(row.Float(7))
		entry.Harvest10 = float32(row.Float(8))
		entry.HarvestCoin = float32(row.Float(9))

		entry.BonusTable = bonusTable == 1
		entries = append(entries, entry)

		return nil
	}, groundspawnID)

	if err != nil {
		return nil, fmt.Errorf("failed to query groundspawn entries: %w", err)
	}

	return entries, nil
}

// LoadGroundSpawnItems loads harvest items for a ground spawn
func (da *DatabaseAdapter) LoadGroundSpawnItems(groundspawnID int32) ([]*GroundSpawnEntryItem, error) {
	query := `
		SELECT item_id, is_rare, grid_id, quantity
		FROM groundspawn_items
		WHERE groundspawn_id = ?
		ORDER BY item_id ASC
	`

	var items []*GroundSpawnEntryItem

	err := da.db.Query(query, func(row *database.Row) error {
		item := &GroundSpawnEntryItem{}

		item.ItemID = int32(row.Int(0))
		item.IsRare = int8(row.Int(1))
		item.GridID = int32(row.Int(2))
		item.Quantity = int16(row.Int(3))

		items = append(items, item)

		return nil
	}, groundspawnID)

	if err != nil {
		return nil, fmt.Errorf("failed to query groundspawn items: %w", err)
	}

	return items, nil
}

// SaveGroundSpawn saves a ground spawn to the database
func (da *DatabaseAdapter) SaveGroundSpawn(gs *GroundSpawn) error {
	if gs == nil {
		return fmt.Errorf("ground spawn cannot be nil")
	}

	query := `
		INSERT OR REPLACE INTO groundspawns (
			id, name, x, y, z, heading, respawn_timer, collection_skill, 
			number_harvests, attempts_per_harvest, groundspawn_entry_id,
			randomize_heading, zone_id, created_at, updated_at
		)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now'))
	`

	randomizeHeading := 0
	if gs.GetRandomizeHeading() {
		randomizeHeading = 1
	}

	// TODO: Get actual zone ID from spawn
	zoneID := int32(1)

	err := da.db.Exec(query,
		gs.GetID(),
		gs.GetName(),
		gs.GetX(),
		gs.GetY(),
		gs.GetZ(),
		int16(gs.GetHeading()),
		300, // Default 5 minutes respawn timer
		gs.GetCollectionSkill(),
		gs.GetNumberHarvests(),
		gs.GetAttemptsPerHarvest(),
		gs.GetGroundSpawnEntryID(),
		randomizeHeading,
		zoneID,
	)

	if err != nil {
		return fmt.Errorf("failed to save ground spawn %d: %w", gs.GetID(), err)
	}

	return nil
}

// LoadAllGroundSpawns loads all ground spawns from the database
func (da *DatabaseAdapter) LoadAllGroundSpawns() ([]*GroundSpawn, error) {
	query := `
		SELECT id, name, x, y, z, heading, collection_skill, number_harvests,
		       attempts_per_harvest, groundspawn_entry_id, randomize_heading
		FROM groundspawns
		WHERE zone_id = ?
		ORDER BY id ASC
	`

	// TODO: Support multiple zones
	zoneID := int32(1)

	var groundSpawns []*GroundSpawn

	err := da.db.Query(query, func(row *database.Row) error {
		id := int32(row.Int(0))
		name := row.Text(1)
		x := float32(row.Float(2))
		y := float32(row.Float(3))
		z := float32(row.Float(4))
		heading := float32(row.Float(5))
		collectionSkill := row.Text(6)
		numberHarvests := int8(row.Int(7))
		attemptsPerHarvest := int8(row.Int(8))
		groundspawnEntryID := int32(row.Int(9))
		randomizeHeading := int32(row.Int(10))

		config := GroundSpawnConfig{
			GroundSpawnID:      groundspawnEntryID,
			CollectionSkill:    collectionSkill,
			NumberHarvests:     numberHarvests,
			AttemptsPerHarvest: attemptsPerHarvest,
			RandomizeHeading:   randomizeHeading == 1,
			Location: SpawnLocation{
				X:       x,
				Y:       y,
				Z:       z,
				Heading: heading,
				GridID:  1, // TODO: Load from database
			},
			Name:        name,
			Description: fmt.Sprintf("A %s node", collectionSkill),
		}

		gs := NewGroundSpawn(config)
		gs.SetID(id)

		groundSpawns = append(groundSpawns, gs)

		return nil
	}, zoneID)

	if err != nil {
		return nil, fmt.Errorf("failed to query groundspawns: %w", err)
	}

	return groundSpawns, nil
}

// DeleteGroundSpawn deletes a ground spawn from the database
func (da *DatabaseAdapter) DeleteGroundSpawn(id int32) error {
	query := `DELETE FROM groundspawns WHERE id = ?`

	err := da.db.Exec(query, id)
	if err != nil {
		return fmt.Errorf("failed to delete ground spawn %d: %w", id, err)
	}

	return nil
}

// LoadPlayerHarvestStatistics loads harvest statistics for a player
func (da *DatabaseAdapter) LoadPlayerHarvestStatistics(playerID int32) (map[string]int64, error) {
	query := `
		SELECT skill_name, harvest_count
		FROM player_harvest_stats
		WHERE player_id = ?
	`

	stats := make(map[string]int64)

	err := da.db.Query(query, func(row *database.Row) error {
		skillName := row.Text(0)
		harvestCount := row.Int64(1)

		stats[skillName] = harvestCount

		return nil
	}, playerID)

	if err != nil {
		return nil, fmt.Errorf("failed to query player harvest stats: %w", err)
	}

	return stats, nil
}

// SavePlayerHarvestStatistic saves a player's harvest statistic
func (da *DatabaseAdapter) SavePlayerHarvestStatistic(playerID int32, skillName string, count int64) error {
	query := `
		INSERT OR REPLACE INTO player_harvest_stats (player_id, skill_name, harvest_count, updated_at)
		VALUES (?, ?, ?, datetime('now'))
	`

	err := da.db.Exec(query, playerID, skillName, count)
	if err != nil {
		return fmt.Errorf("failed to save player harvest stat: %w", err)
	}

	return nil
}
