package database

import (
	"context"
	"database/sql"
	"time"

	"git.eeqj.de/sneak/routewatch/internal/logger"
)

const slowQueryThreshold = 25 * time.Millisecond

// logSlowQuery logs queries that take longer than slowQueryThreshold
func logSlowQuery(logger *logger.Logger, query string, start time.Time) {
	elapsed := time.Since(start)
	if elapsed > slowQueryThreshold {
		logger.Debug("Slow query", "query", query, "duration", elapsed)
	}
}

// queryRow wraps QueryRow with slow query logging
// nolint:unused // kept for consistency with other query wrappers
func (d *Database) queryRow(query string, args ...interface{}) *sql.Row {
	start := time.Now()
	defer logSlowQuery(d.logger, query, start)

	return d.db.QueryRow(query, args...)
}

// query wraps Query with slow query logging
// nolint:unused // kept for future use to ensure all queries go through slow query logging
func (d *Database) query(query string, args ...interface{}) (*sql.Rows, error) {
	start := time.Now()
	defer logSlowQuery(d.logger, query, start)

	return d.db.Query(query, args...)
}

// exec wraps Exec with slow query logging
func (d *Database) exec(query string, args ...interface{}) error {
	start := time.Now()
	defer logSlowQuery(d.logger, query, start)

	_, err := d.db.Exec(query, args...)

	return err
}

// loggingTx wraps sql.Tx to log slow queries
type loggingTx struct {
	*sql.Tx
	logger *logger.Logger
}

// QueryRow wraps sql.Tx.QueryRow to log slow queries
func (tx *loggingTx) QueryRow(query string, args ...interface{}) *sql.Row {
	start := time.Now()
	defer logSlowQuery(tx.logger, query, start)

	return tx.Tx.QueryRow(query, args...)
}

// Query wraps sql.Tx.Query to log slow queries
func (tx *loggingTx) Query(query string, args ...interface{}) (*sql.Rows, error) {
	start := time.Now()
	defer logSlowQuery(tx.logger, query, start)

	return tx.Tx.Query(query, args...)
}

// QueryContext wraps sql.Tx.QueryContext to log slow queries
func (tx *loggingTx) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
	start := time.Now()
	defer logSlowQuery(tx.logger, query, start)

	return tx.Tx.QueryContext(ctx, query, args...)
}

// QueryRowContext wraps sql.Tx.QueryRowContext to log slow queries
func (tx *loggingTx) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
	start := time.Now()
	defer logSlowQuery(tx.logger, query, start)

	return tx.Tx.QueryRowContext(ctx, query, args...)
}

// Exec wraps sql.Tx.Exec to log slow queries
func (tx *loggingTx) Exec(query string, args ...interface{}) (sql.Result, error) {
	start := time.Now()
	defer logSlowQuery(tx.logger, query, start)

	return tx.Tx.Exec(query, args...)
}

// ExecContext wraps sql.Tx.ExecContext to log slow queries
func (tx *loggingTx) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
	start := time.Now()
	defer logSlowQuery(tx.logger, query, start)

	return tx.Tx.ExecContext(ctx, query, args...)
}
