package jobqueue

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

func NewDBRunnableFromMap(data map[string]interface{}) (*DBRunnable, error) {
	t, ok := data["type"].(string)
	if !ok {
		return nil, fmt.Errorf("%w: Invalid Type: %v", ErrInvalidData, data["type"])
	}

	dsn, ok := data["dsn"].(string)
	if !ok {
		return nil, fmt.Errorf("%w: Invalid DSN: %v", ErrInvalidData, data["dsn"])
	}

	query, ok := data["query"].(string)
	if !ok {
		return nil, fmt.Errorf("%w: Invalid Query: %v", ErrInvalidData, data["query"])
	}

	return &DBRunnable{
		Type:  t,
		DSN:   dsn,
		Query: query,
	}, nil
}

// DBResult is a result of a db query
type DBResult struct {
	RowsAffected int
}

type DBRunnable struct {
	Type  string
	DSN   string
	Query string
	db    *gorm.DB // internal for testing
}

func (d *DBRunnable) Run() (RunResult[DBResult], error) {
	var db *gorm.DB
	var err error

	if d.db == nil {

		switch d.Type {
		case "mysql":
			db, err = gorm.Open(mysql.Open(d.DSN), &gorm.Config{})

		default:
			return RunResult[DBResult]{Status: ResultStatusFailed}, ErrUnsupportedDatabaseType
		}
	} else {
		db = d.db
	}

	if err != nil {
		return RunResult[DBResult]{Status: ResultStatusFailed}, err
	}

	var result *gorm.DB

	result = db.Exec(d.Query)

	if result.Error != nil {
		return RunResult[DBResult]{Status: ResultStatusFailed}, result.Error
	}

	return RunResult[DBResult]{
		Status: ResultStatusSuccess,
		Data: DBResult{
			RowsAffected: int(result.RowsAffected),
		},
	}, nil
}