package helper

import (
	"book-store-api/logger"
	"database/sql"
)

// Transaction is an interface that models the standard transaction in
// `database/sql`.

// To ensure `TxFn` funcs cannot commit or rollback a transaction (which is
// handled by `WithTransaction`), those methods are not included here.
type Transaction interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
	Prepare(query string) (*sql.Stmt, error)
	Query(query string, args ...interface{}) (*sql.Rows, error)
	QueryRow(query string, args ...interface{}) *sql.Row
}

// A Txfn is a function that will be called with an initialized `Transaction` object
// that can be used for executing statements and queries against a database.
type TxFn func(Transaction) error

// WithTransaction creates a new transaction and handles rollback/commit based on the
// error object returned by the `TxFn`
func WithTransaction(db *sql.DB, fn TxFn) (err error) {
	tx, err := db.Begin()
	if err != nil {
		return
	}

	defer func() {
		if pn := recover(); pn != nil {
			tx.Rollback()
			logger.Errorf("Error While processing Transaction", pn, err.Error())
			panic(pn)
		} else if err != nil {
			// something went wrong, rollback
			logger.Errorf("Error While processing Transaction", err, err.Error())
			tx.Rollback()
		} else {
			// all good, commit
			err = tx.Commit()
		}
	}()

	err = fn(tx)
	return err
}
