package mocks

import (
	"encoding/json"
	"time"

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

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

type MockFingerprintParams struct {
	Serial string
	Time   time.Time
}

func (m *MockFingerprintParams) ManifestSerial() string {
	return m.Serial
}

func (m *MockFingerprintParams) CurTime() time.Time {
	return m.Time
}

type MockUpdateManifests struct {
	queries.QueryBase
	SelectResponse      []common.UpdateManifest
	SelectByVINResponse []common.StatusManifest
	LoadResponse        *common.UpdateManifest
	ECUUpdatesMock      func(man *common.UpdateManifestECU, vin string) ([]*common.UpdateManifestECU, error)
	FlashPackManifest   common.UpdateManifest
	DBMockHelper
}

func (m *MockUpdateManifests) Count(filter common.UpdateManifest) (int, error) {
	return len(m.SelectResponse), m.Error
}

func (m *MockUpdateManifests) Delete(manifest *common.UpdateManifest) (orm.Result, error) {
	err := validator.ValidateIDField(manifest.ID)
	if err != nil {
		return nil, err
	}

	return m.ORMResponse, m.Error
}

func (m *MockUpdateManifests) Insert(manifest *common.UpdateManifest) (orm.Result, error) {
	manifest.ID += 1
	return m.ORMResponse, m.Error
}

func (m *MockUpdateManifests) ECUInsert(ecu *common.UpdateManifestECU) (orm.Result, error) {
	ecu.ID = 1
	return m.ORMResponse, m.Error
}

func (m *MockUpdateManifests) FileInsert(file *common.UpdateManifestFile) (orm.Result, error) {
	return m.ORMResponse, m.Error
}

func (m *MockUpdateManifests) Select(filter *common.UpdateManifest, paging *queries.PageQueryOptions) ([]common.UpdateManifest, error) {
	m.LastFilter = filter
	m.LastPaging = paging

	return m.SelectResponse, m.Error
}

func (m *MockUpdateManifests) Archive(ids []int64, active bool) (orm.Result, error) {
	return m.ORMResponse, m.Error
}

func (m *MockUpdateManifests) SelectByVIN(vin string, paging *queries.PageQueryOptions) ([]common.StatusManifest, error) {
	m.LastPaging = paging

	return m.SelectByVINResponse, m.Error
}

func (m *MockUpdateManifests) Update(manifest *common.UpdateManifest) (orm.Result, error) {
	m.LastFilter = manifest

	return m.ORMResponse, m.Error
}

func (m *MockUpdateManifests) Load(manifest *common.UpdateManifest) error {
	m.LastFilter = manifest

	if m.LoadResponse != nil {
		m.LoadResponse.ID = manifest.ID
		data, err := json.Marshal(m.LoadResponse)
		if err != nil {
			return errors.WithStack(err)
		}
		err = json.Unmarshal(data, manifest)
		if err != nil {
			return errors.WithStack(err)
		}
	}

	return m.Error
}

func (m *MockUpdateManifests) Search(filter common.UpdateManifestSearch, paging *queries.PageQueryOptions) ([]common.UpdateManifest, error) {
	m.LastFilter = &filter
	m.LastPaging = paging

	return m.SelectResponse, m.Error
}

func (m *MockUpdateManifests) SearchCount(filter common.UpdateManifestSearch) (int, error) {
	m.LastFilter = &filter

	return len(m.SelectResponse), m.Error
}

func (m *MockUpdateManifests) SetListResp(list interface{}) {
	if list != nil {
		m.SelectResponse = list.([]common.UpdateManifest)
	} else {
		m.SelectResponse = nil
	}
}

func (m *MockUpdateManifests) ECURollback(man *common.UpdateManifestECU, vin string) ([]*common.UpdateManifestECU, error) {
	return m.ECUUpdatesMock(man, vin)
}

func (m *MockUpdateManifests) AddSUMSVersion(manifest *common.UpdateManifest) (orm.Result, error) {
	return m.ORMResponse, m.Error
}

func (m *MockUpdateManifests) SelectFlashPackByVersion(versionNumber string) (manifest common.UpdateManifest, err error) {
	return m.FlashPackManifest, nil
}
