package sql

import (
	"database/sql"

	"github.com/acronis/perfkit/db"
)

// sqlResult wraps sql.Result to implement the db.Result interface
type sqlResult struct {
	result sql.Result // Underlying SQL result
}

// LastInsertId returns the ID generated by an INSERT operation
// Implements db.Result interface
func (r *sqlResult) LastInsertId() (int64, error) {
	return r.result.LastInsertId()
}

// RowsAffected returns the number of rows affected by the operation
// Implements db.Result interface
func (r *sqlResult) RowsAffected() (int64, error) {
	return r.result.RowsAffected()
}

// Exec executes a query that doesn't return rows
// Implements querier.execContext through sqlGateway
// Parameters:
//   - format: SQL query string with placeholders
//   - args: Values for the placeholders
//
// Returns:
//   - db.Result: Wrapper around sql.Result
//   - error: Any error that occurred during execution
func (g *sqlGateway) Exec(format string, args ...interface{}) (db.Result, error) {
	var sqlRes, err = g.rw.execContext(g.ctx, format, args...)
	return &sqlResult{result: sqlRes}, err
}

// QueryRow executes a query that returns a single row
// Implements querier.queryRowContext through sqlGateway
// Supports EXPLAIN mode using dialect interface
// Parameters:
//   - format: SQL query string with placeholders
//   - args: Values for the placeholders
//
// Returns:
//   - db.Row: Interface for scanning row values
func (g *sqlGateway) QueryRow(format string, args ...interface{}) db.Row {
	if g.explain {
		var err error
		// Use dialect interface to get database-specific EXPLAIN syntax
		if format, err = addExplainPrefix(g.dialect.name(), format); err != nil {
			return &db.EmptyRow{}
		}

		var rows *sql.Rows
		// Execute EXPLAIN query using querier interface
		if rows, err = g.rw.queryContext(g.ctx, format, args...); err != nil {
			return &db.EmptyRow{}
		}

		// Log EXPLAIN results if logger is configured
		if g.explainLogger != nil {
			if err = logExplainResults(g.explainLogger, g.dialect.name(), rows, format, args...); err != nil {
				return &db.EmptyRow{}
			}
		}
	}

	// Execute actual query using querier interface
	var row = g.rw.queryRowContext(g.ctx, format, args...)
	return &wrappedRow{row: row, logTime: g.LogTime, readRowsLogger: g.readRowsLogger}
}

// Query executes a query that returns multiple rows
// Implements querier.queryContext through sqlGateway
// Supports EXPLAIN mode using dialect interface
// Parameters:
//   - format: SQL query string with placeholders
//   - args: Values for the placeholders
//
// Returns:
//   - db.Rows: Interface for iterating over result rows
//   - error: Any error that occurred during execution
func (g *sqlGateway) Query(format string, args ...interface{}) (db.Rows, error) {
	if g.explain {
		var err error
		// Use dialect interface to get database-specific EXPLAIN syntax
		if format, err = addExplainPrefix(g.dialect.name(), format); err != nil {
			return &db.EmptyRows{}, err
		}
	}

	// Execute query using querier interface
	var rows, err = g.rw.queryContext(g.ctx, format, args...)
	if err != nil {
		return rows, err
	}

	// Log EXPLAIN results if in explain mode and logger is configured
	if g.explain && g.explainLogger != nil {
		if err = logExplainResults(g.explainLogger, g.dialect.name(), rows, format, args...); err != nil {
			return &db.EmptyRows{}, err
		}
	}

	return &wrappedRows{rows: rows, logTime: g.LogTime, readRowsLogger: g.readRowsLogger}, err
}
