package mocks

import (
	"time"

	"github.com/go-pg/pg/v10/orm"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/db/queries"
	"github.com/fiskerinc/cloud-services/pkg/validator"
)

type MockCarUpdates struct {
	SelectCarUpdateResponse                  *common.CarUpdate
	SelectCarUpdatesResponse                 []common.CarUpdate
	SelectCarUpdateStatusesResponse          []common.CarUpdateStatus
	HasPendingUpdatesResponse                bool
	LoadManifest                             *common.UpdateManifest
	PendingUpdateSameAfterSalesUsersResponse PendingUpdatesFromSameAftersaleUserResponse
	DBMockHelper
}

func (c *MockCarUpdates) HasPendingUpdatesFromAftersalesUser(manifestID int64, vin string) (updateID int64, pendingUpdateSameUser bool, err error) {
	return c.PendingUpdateSameAfterSalesUsersResponse.UpdateID, c.PendingUpdateSameAfterSalesUsersResponse.PendingUpdateSameUser, c.PendingUpdateSameAfterSalesUsersResponse.Err
}

type PendingUpdatesFromSameAftersaleUserResponse struct {
	PendingUpdateSameUser bool
	UpdateID              int64
	Err                   error
}

func (c *MockCarUpdates) SelectByID(id int64) (*common.CarUpdate, error) {
	return c.SelectCarUpdateResponse, c.Error
}

func (c *MockCarUpdates) SelectByVIN(vin string) ([]common.CarUpdate, error) {
	return c.SelectCarUpdatesResponse, c.Error
}

func (c *MockCarUpdates) SelectMostRecentByVINs(vins []string) ([]common.CarUpdate, error) {
	return c.SelectCarUpdatesResponse, c.Error
}

func (c *MockCarUpdates) SelectByManifestID(manifest_id int64) ([]common.CarUpdate, error) {
	return c.SelectCarUpdatesResponse, c.Error
}

func (c *MockCarUpdates) SelectOrInsert(update *common.CarUpdate) (bool, error) {
	update.ID++
	return c.SelectOrInsertResult, c.Error
}

func (c *MockCarUpdates) Select(filter *common.CarUpdate, paging *queries.PageQueryOptions) ([]common.CarUpdate, error) {
	c.LastFilter = filter
	c.LastPaging = paging

	return c.SelectCarUpdatesResponse, c.Error
}

func (c *MockCarUpdates) Delete(update *common.CarUpdate) (orm.Result, error) {
	err := validator.ValidateIDField(update.ID)
	if err != nil {
		return nil, err
	}

	return c.ORMResponse, c.Error
}

func (c *MockCarUpdates) UpdateStatus(update *common.CarUpdate) (orm.Result, error) {
	err := validator.ValidateIDField(update.ID)
	if err != nil {
		return nil, err
	}

	update.UpdatedAt = &time.Time{}

	return c.ORMResponse, c.Error
}

func (c *MockCarUpdates) Insert(update *common.CarUpdate) (orm.Result, error) {
	update.ID++
	return c.ORMResponse, c.Error
}

func (c *MockCarUpdates) Load(update *common.CarUpdate) error {
	if c.Error != nil {
		return c.Error
	}

	if c.SelectCarUpdateResponse != nil {
		update.VIN = c.SelectCarUpdateResponse.VIN
		update.UpdateManifestID = c.SelectCarUpdateResponse.UpdateManifestID
	}

	if c.LoadManifest == nil {
		update.UpdateManifest = &common.UpdateManifest{
			ID:           update.UpdateManifestID,
			Name:         "Test",
			Version:      "1.2",
			ReleaseNotes: "http://releasenotes.com",
		}
	} else {
		update.UpdateManifest = c.LoadManifest
	}

	return nil
}

func (c *MockCarUpdates) Count(filter *common.CarUpdate) (int, error) {
	return len(c.SelectCarUpdatesResponse), c.Error
}

func (c *MockCarUpdates) GetUpdateStatuses(carupdateid int64, paging *queries.PageQueryOptions) ([]common.CarUpdateStatus, error) {
	c.LastPaging = paging

	return c.SelectCarUpdateStatusesResponse, c.Error
}

func (c *MockCarUpdates) TruncateRequirementsAwaitForUpdate(carupdateid int64) (orm.Result, error) {
	return c.ORMResponse, c.Error
}

func (c *MockCarUpdates) CountUpdateStatuses(carupdateid int64) (int, error) {
	return len(c.SelectCarUpdateStatusesResponse), c.Error
}

func (c *MockCarUpdates) GetManifest(carupdateid int64) (*common.UpdateManifest, error) {
	if c.LoadManifest == nil {
		return nil, c.Error
	}
	return c.LoadManifest, c.Error
}

func (c *MockCarUpdates) LogStatus(update *common.CarUpdate) (orm.Result, error) {
	return c.ORMResponse, c.Error
}

func (c *MockCarUpdates) SetLoadResp(item interface{}) {
	if item == nil {
		c.SelectCarUpdateResponse = nil
	} else {
		c.SelectCarUpdateResponse = item.(*common.CarUpdate)
	}
}

func (c *MockCarUpdates) SetListResp(list interface{}) {
	if list != nil {
		c.SelectCarUpdatesResponse = list.([]common.CarUpdate)
	} else {
		c.SelectCarUpdatesResponse = nil
	}
}

func (c *MockCarUpdates) HasPendingUpdates(manifestID int64, vin string) (bool, error) {
	return c.HasPendingUpdatesResponse, c.Error
}

var lastStatus string

func (c *MockCarUpdates) UpdateStatusIfNotRepeat(update *common.CarUpdate) (orm.Result, error) {
	if update.Status == lastStatus {
		return nil, queries.RepeatedStatus
	}

	lastStatus = update.Status
	return nil, nil
}

func (c *MockCarUpdates) InsertAndCreateStatus(update *common.CarUpdate) (orm.Result, error) {
	update.ID++
	return c.ORMResponse, c.Error
}

func (c *MockCarUpdates) InsertMissingFlashpack(vin string, flashpackVersion string) (err error) {
	return nil
}

var _ queries.CarUpdatesInterface = &MockCarUpdates{}
