package repository

import (
	"context"
	"sno/internal/models"

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

// RewardRepository defines the interface for reward data operations.
type RewardRepository interface {
	Create(ctx context.Context, reward *models.Reward) (*models.Reward, error)
	GetAllActive(ctx context.Context) ([]models.Reward, error)
	GetByID(ctx context.Context, id int) (*models.Reward, error)
	UpdateStock(ctx context.Context, id int, quantity int) error
	Update(ctx context.Context, id int, reward *models.Reward) (*models.Reward, error)
	Delete(ctx context.Context, id int) error
}

// postgresRewardRepository implements the RewardRepository interface.
type postgresRewardRepository struct {
	db *pgxpool.Pool
}

// NewRewardRepository creates a new instance of a reward repository.
func NewRewardRepository(db *pgxpool.Pool) RewardRepository {
	return &postgresRewardRepository{db: db}
}

// Create inserts a new reward into the database.
func (r *postgresRewardRepository) Create(ctx context.Context, reward *models.Reward) (*models.Reward, error) {
	query := `
		INSERT INTO rewards (title, description, image_url, price_stars, delivery_type, instructions, stock, created_by)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
		RETURNING id, is_active, created_at
	`
	err := r.db.QueryRow(ctx, query,
		reward.Title, reward.Description, reward.ImageURL, reward.PriceStars, reward.DeliveryType, reward.Instructions, reward.Stock, reward.CreatedBy,
	).Scan(&reward.ID, &reward.IsActive, &reward.CreatedAt)

	if err != nil {
		return nil, err
	}

	return reward, nil
}

// GetAllActive retrieves all active rewards that are in stock.
func (r *postgresRewardRepository) GetAllActive(ctx context.Context) ([]models.Reward, error) {
	query := `
		SELECT id, title, description, image_url, price_stars, delivery_type, instructions, stock, is_active, created_at
		FROM rewards
		WHERE is_active = true AND (stock > 0 OR stock = -1) -- Using -1 for infinite stock
		ORDER BY price_stars ASC
	`
	rows, err := r.db.Query(ctx, query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var rewards []models.Reward
	for rows.Next() {
		var p models.Reward
		if err := rows.Scan(&p.ID, &p.Title, &p.Description, &p.ImageURL, &p.PriceStars, &p.DeliveryType, &p.Instructions, &p.Stock, &p.IsActive, &p.CreatedAt); err != nil {
			return nil, err
		}
		rewards = append(rewards, p)
	}

	if err := rows.Err(); err != nil {
		return nil, err
	}

	if rewards == nil {
		return []models.Reward{}, nil
	}

	return rewards, nil
}

// GetByID retrieves a single reward by its ID.
func (r *postgresRewardRepository) GetByID(ctx context.Context, id int) (*models.Reward, error) {
	query := `
		SELECT id, title, description, image_url, price_stars, delivery_type, instructions, stock, is_active, created_at, created_by
		FROM rewards
		WHERE id = $1
	`
	var p models.Reward
	err := r.db.QueryRow(ctx, query, id).Scan(
		&p.ID, &p.Title, &p.Description, &p.ImageURL, &p.PriceStars, &p.DeliveryType, &p.Instructions, &p.Stock, &p.IsActive, &p.CreatedAt, &p.CreatedBy,
	)
	if err != nil {
		return nil, err
	}
	return &p, nil
}

// UpdateStock updates the stock for a given reward.
func (r *postgresRewardRepository) UpdateStock(ctx context.Context, id int, quantity int) error {
	query := `UPDATE rewards SET stock = stock - $1 WHERE id = $2 AND stock != -1` // -1 is infinite stock
	querier := getQuerier(ctx, r.db)
	_, err := querier.Exec(ctx, query, quantity, id)
	return err
}

// Update updates an existing reward
func (r *postgresRewardRepository) Update(ctx context.Context, id int, reward *models.Reward) (*models.Reward, error) {
	query := `
		UPDATE rewards
		SET title = $2, description = $3, image_url = $4, price_stars = $5,
			delivery_type = $6, instructions = $7, stock = $8, is_active = $9
		WHERE id = $1
		RETURNING id, title, description, image_url, price_stars, delivery_type, instructions, stock, is_active, created_at, created_by
	`

	var p models.Reward
	err := r.db.QueryRow(ctx, query,
		id, reward.Title, reward.Description, reward.ImageURL, reward.PriceStars,
		reward.DeliveryType, reward.Instructions, reward.Stock, reward.IsActive,
	).Scan(
		&p.ID, &p.Title, &p.Description, &p.ImageURL, &p.PriceStars,
		&p.DeliveryType, &p.Instructions, &p.Stock, &p.IsActive, &p.CreatedAt, &p.CreatedBy,
	)

	if err != nil {
		return nil, err
	}

	return &p, nil
}

// Delete deletes a reward
func (r *postgresRewardRepository) Delete(ctx context.Context, id int) error {
	query := `DELETE FROM rewards WHERE id = $1`
	_, err := r.db.Exec(ctx, query, id)
	return err
}