package storage

import (
	"context"
	"fmt"
	"time"

	"github.com/jackc/pgx/v5/pgxpool"
)

// LogEntry represents a single adventure log message.
type LogEntry struct {
	ID        int64     `json:"id"`
	HeroID    int64     `json:"heroId"`
	Message   string    `json:"message"`
	CreatedAt time.Time `json:"createdAt"`
}

// LogStore handles adventure log CRUD operations against PostgreSQL.
type LogStore struct {
	pool *pgxpool.Pool
}

// NewLogStore creates a new LogStore backed by the given connection pool.
func NewLogStore(pool *pgxpool.Pool) *LogStore {
	return &LogStore{pool: pool}
}

// Add inserts a new adventure log entry for the given hero.
func (s *LogStore) Add(ctx context.Context, heroID int64, message string) error {
	_, err := s.pool.Exec(ctx,
		`INSERT INTO adventure_log (hero_id, message) VALUES ($1, $2)`,
		heroID, message,
	)
	if err != nil {
		return fmt.Errorf("add log entry: %w", err)
	}
	return nil
}

// GetSince returns log entries for a hero created after the given timestamp,
// ordered oldest-first (chronological). Used to build offline reports from
// real adventure log entries written by the offline simulator.
func (s *LogStore) GetSince(ctx context.Context, heroID int64, since time.Time, limit int) ([]LogEntry, error) {
	if limit <= 0 {
		limit = 200
	}
	if limit > 500 {
		limit = 500
	}

	rows, err := s.pool.Query(ctx, `
		SELECT id, hero_id, message, created_at
		FROM adventure_log
		WHERE hero_id = $1 AND created_at > $2
		ORDER BY created_at ASC
		LIMIT $3
	`, heroID, since, limit)
	if err != nil {
		return nil, fmt.Errorf("get log since: %w", err)
	}
	defer rows.Close()

	var entries []LogEntry
	for rows.Next() {
		var e LogEntry
		if err := rows.Scan(&e.ID, &e.HeroID, &e.Message, &e.CreatedAt); err != nil {
			return nil, fmt.Errorf("scan log entry: %w", err)
		}
		entries = append(entries, e)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("log since rows: %w", err)
	}
	if entries == nil {
		entries = []LogEntry{}
	}
	return entries, nil
}

// GetRecent returns the most recent log entries for a hero, ordered newest-first.
func (s *LogStore) GetRecent(ctx context.Context, heroID int64, limit int) ([]LogEntry, error) {
	if limit <= 0 {
		limit = 50
	}
	if limit > 200 {
		limit = 200
	}

	rows, err := s.pool.Query(ctx, `
		SELECT id, hero_id, message, created_at
		FROM adventure_log
		WHERE hero_id = $1
		ORDER BY created_at DESC
		LIMIT $2
	`, heroID, limit)
	if err != nil {
		return nil, fmt.Errorf("get recent log: %w", err)
	}
	defer rows.Close()

	var entries []LogEntry
	for rows.Next() {
		var e LogEntry
		if err := rows.Scan(&e.ID, &e.HeroID, &e.Message, &e.CreatedAt); err != nil {
			return nil, fmt.Errorf("scan log entry: %w", err)
		}
		entries = append(entries, e)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("log entries rows: %w", err)
	}
	if entries == nil {
		entries = []LogEntry{}
	}
	return entries, nil
}
