package repositories

import (
	"context"
	"fmt"

	"github.com/CubeCraft-Creations/Extrudex/backend/internal/models"
	"github.com/jackc/pgx/v5/pgxpool"
)

// UsageLogRepository handles database queries for usage_logs.
type UsageLogRepository struct {
	pool *pgxpool.Pool
}

// NewUsageLogRepository creates a UsageLogRepository backed by the given pool.
func NewUsageLogRepository(pool *pgxpool.Pool) *UsageLogRepository {
	return &UsageLogRepository{pool: pool}
}

// UsageLogFilter holds query parameters for listing usage logs.
type UsageLogFilter struct {
	SpoolID *int // filter by filament_spool_id
	JobID   *int // filter by print_job_id
	Limit   int
	Offset  int
}

// GetAll returns usage logs matching the given filters, with pagination.
func (r *UsageLogRepository) GetAll(ctx context.Context, filter UsageLogFilter) ([]models.UsageLog, int, error) {
	conditions := []string{"1=1"}
	args := []interface{}{}
	argIdx := 1

	if filter.SpoolID != nil {
		conditions = append(conditions, fmt.Sprintf("ul.filament_spool_id = $%d", argIdx))
		args = append(args, *filter.SpoolID)
		argIdx++
	}
	if filter.JobID != nil {
		conditions = append(conditions, fmt.Sprintf("ul.print_job_id = $%d", argIdx))
		args = append(args, *filter.JobID)
		argIdx++
	}

	whereClause := "WHERE " + fmt.Sprintf("%s", conditions[0])
	for _, c := range conditions[1:] {
		whereClause += " AND " + c
	}

	// Count.
	var total int
	countQuery := "SELECT COUNT(*) FROM usage_logs ul " + whereClause
	if err := r.pool.QueryRow(ctx, countQuery, args...).Scan(&total); err != nil {
		return nil, 0, err
	}

	// Query with pagination.
	dataQuery := `SELECT id, print_job_id, filament_spool_id, mm_extruded,
	       grams_used, cost_usd, logged_at, created_at
	FROM usage_logs ul
	` + whereClause +
		" ORDER BY ul.logged_at DESC" +
		fmt.Sprintf(" LIMIT $%d OFFSET $%d", argIdx, argIdx+1)

	dataArgs := make([]interface{}, len(args))
	copy(dataArgs, args)
	dataArgs = append(dataArgs, filter.Limit, filter.Offset)

	rows, err := r.pool.Query(ctx, dataQuery, dataArgs...)
	if err != nil {
		return nil, 0, err
	}
	defer rows.Close()

	var logs []models.UsageLog
	for rows.Next() {
		var l models.UsageLog
		if err := rows.Scan(
			&l.ID, &l.PrintJobID, &l.FilamentSpoolID,
			&l.MMExtruded, &l.GramsUsed, &l.CostUSD,
			&l.LoggedAt, &l.CreatedAt,
		); err != nil {
			return nil, 0, err
		}
		logs = append(logs, l)
	}
	if err := rows.Err(); err != nil {
		return nil, 0, err
	}
	if logs == nil {
		logs = []models.UsageLog{}
	}

	return logs, total, nil
}
