package queries

import (
	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/validator"

	"github.com/go-pg/pg/v10/orm"
	"github.com/pkg/errors"
)

type DriversInterface interface {
	Delete(driver *common.Driver) (orm.Result, error)
	Insert(driver *common.Driver) (orm.Result, error)
	Select(filter *common.Driver) ([]common.Driver, error)
	SelectOrInsert(driver *common.Driver) (bool, error)
	Load(driver *common.Driver) error
}

type Drivers struct {
	QueryBase
}

// Select returns list of drivers
func (d *Drivers) Select(filter *common.Driver) ([]common.Driver, error) {
	drivers := []common.Driver{}
	query := d.GetDBConn().Model(&drivers)

	d.selectFilter(query, filter)

	err := query.Select()

	return drivers, errors.WithStack(err)
}

func (d *Drivers) SelectOrInsert(driver *common.Driver) (bool, error) {
	q := d.GetDBConn().Model(driver)

	if driver.ID != "" {
		q.Where("id = ?id")
	} else {
		return false, errors.New("no ID")
	}

	inserted, err := q.SelectOrInsert()

	return inserted, errors.WithStack(err)
}

func (d *Drivers) selectFilter(query *orm.Query, filter *common.Driver) {
	if filter.ID != "" {
		query.Where("ID = ?", filter.ID)
	}
}

func (d *Drivers) Insert(driver *common.Driver) (orm.Result, error) {

	err := validator.ValidateStruct(driver)
	if err != nil {
		return nil, errors.WithStack(err)
	}

	result, err := d.GetDBConn().Model(driver).Insert()

	return result, errors.WithStack(err)
}

func (d *Drivers) Delete(driver *common.Driver) (orm.Result, error) {
	if driver.ID == "" {
		return nil, errors.WithStack(&validator.FieldError{
			ErrorMsg: "ID required",
		})
	}

	tx, err := d.GetDBConn().Begin()
	if err != nil {
		return nil, errors.WithStack(err)
	}
	defer tx.Close()

	cardrivers := common.CarToDriver{
		DriverID: driver.ID,
	}
	_, err = tx.Model(&cardrivers).Where("driverId = ?driverId").Delete()
	if err != nil {
		tx.Rollback()
		return nil, errors.WithStack(err)
	}

	result, err := tx.Model(driver).WherePK().Delete()
	if err != nil {
		tx.Rollback()
		return nil, errors.WithStack(err)
	}

	err = tx.Commit()

	return result, errors.WithStack(err)
}

func (d *Drivers) Load(driver *common.Driver) error {
	query := d.GetDBConn().Model(driver)

	err := query.Select()
	if err != nil {
		return errors.WithStack(err)
	}

	return nil
}
