package queries_test

import (
	"testing"

	m "github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/db"
	"github.com/fiskerinc/cloud-services/pkg/db/queries"
	th "github.com/fiskerinc/cloud-services/pkg/testhelper"

	"github.com/google/uuid"
)

const testSubPackageName = "TESTSUBPACKAGE"

func TestSubscriptionPackagesIntegration(t *testing.T) {
	t.Skip()
	qsp := setupSubscriptionPackages()
	qsf := &queries.SubscriptionFeatures{}
	qsc := &queries.SubscriptionConfigurations{}

	pack := testSubscriptionPackageInsert(t, qsp)
	if pack.ID == uuid.Nil {
		t.Error("unable to create package")
		return
	}

	feature := testSubscriptionPackageFeatureInsert(t, qsf)
	if feature.ID == uuid.Nil {
		t.Error("unable to create feature")
		return
	}

	config, err := testSubscriptionAddConfiguration(t, qsc, &feature)
	if err != nil {
		t.Error("unable to create configuration")
		return
	}

	testSubscriptionAddFeature(t, qsp, &pack, &feature)
	testSubscriptionPackageSelect(t, qsp, &pack)
	testSubscriptionFeatureSelect(t, qsf, &feature)
	testSubscriptionConfigurationSelect(t, qsc, &config)
	testSubscriptionPackageCount(t, qsp, &pack)
	testSubscriptionFeatureCount(t, qsf, &feature)
	testSubscriptionConfigurationCount(t, qsc, &config)
	testSubscriptionPackageUpdate(t, qsp, &pack)
	testSubscriptionFeatureUpdate(t, qsf, &feature)
	testSubscriptionConfigurationUpdate(t, qsc, &config)
	testSubscriptionFeatureLoad(t, qsf, &feature)
	testSubscriptionPackageLoad(t, qsp, &pack)
	testSubscriptionPackageDelete(t, qsp, &pack)
	testSubscriptionFeatureDelete(t, qsf, &feature)
	testSubscriptionConfigDelete(t, qsc, &config)
}

func setupSubscriptionPackages() queries.SubscriptionPackagesInterface {
	instance := &queries.SubscriptionPackages{}
	conn = instance.GetDBConn()
	conn.AddQueryHook(db.SQLLogger{})
	client := instance.GetClient()
	client.InitSchema([]interface{}{
		(*m.SubscriptionPackageToFeature)(nil),
		(*m.SubscriptionPackage)(nil),
		(*m.SubscriptionFeature)(nil),
		(*m.SubscriptionConfiguration)(nil),
	})

	return instance
}

func testSubscriptionPackageInsert(t *testing.T, q queries.SubscriptionPackagesInterface) m.SubscriptionPackage {
	model := m.SubscriptionPackage{Name: testSubPackageName}

	result, err := q.Insert(&model)

	if th.NoError(t, "Insert Package error", err) {
		return model
	}
	th.Equal(t, "Insert Package affected", 1, result.RowsAffected())
	th.Equal(t, "Insert Package returned", 1, result.RowsReturned())

	return model
}

func testSubscriptionPackageFeatureInsert(t *testing.T, q queries.SubscriptionFeaturesInterface) m.SubscriptionFeature {
	feature := m.SubscriptionFeature{
		Name:        testSubPackageName,
		Description: "Test Description",
	}

	result, err := q.Insert(&feature)

	if th.NoError(t, "Insert Feature error", err) {
		return feature
	}
	th.Equal(t, "Insert Feature affected", 1, result.RowsAffected())
	th.Equal(t, "Insert Feature returned", 1, result.RowsReturned())

	return feature
}

func testSubscriptionAddFeature(t *testing.T, q queries.SubscriptionPackagesInterface, p *m.SubscriptionPackage, f *m.SubscriptionFeature) {
	result, err := q.AddFeature(p, f)

	th.NoError(t, "AddFeature error", err)
	th.True(t, "AddFeature result", result)
}

func testSubscriptionAddConfiguration(t *testing.T, q queries.SubscriptionConfigurationsInterface, f *m.SubscriptionFeature) (m.SubscriptionConfiguration, error) {
	model := m.SubscriptionConfiguration{
		SubscriptionFeatureID: f.ID,
		ECU:                   "TEST",
		SoftwareVersion:       "SOFTWAREVERSION",
		HardwareVersion:       "HARDWAREVERSION",
		Configuration:         &m.BinaryHex{0x99},
		DID:                   &m.BinaryHex{0x01},
		PID:                   &m.BinaryHex{0x02},
		Mask:                  &m.BinaryHex{0x03},
	}

	result, err := q.Insert(&model)

	if th.NoError(t, "Insert Config error", err) {
		return model, err
	}
	th.Equal(t, "Insert Config affected", 1, result.RowsAffected())
	th.Equal(t, "Insert Config returned", 1, result.RowsReturned())

	return model, nil
}

func testSubscriptionPackageUpdate(t *testing.T, q queries.SubscriptionPackagesInterface, model *m.SubscriptionPackage) {
	model.Name = model.Name + "X"
	result, err := q.Update(model)

	if th.NoError(t, "Update Package error", err) {
		return
	}
	th.Equal(t, "Update Package affected", 1, result.RowsAffected())
	th.Equal(t, "Update Package returned", 0, result.RowsReturned())
}

func testSubscriptionFeatureUpdate(t *testing.T, q queries.SubscriptionFeaturesInterface, model *m.SubscriptionFeature) {
	result, err := q.Update(model)

	if th.NoError(t, "Update Feature error", err) {
		return
	}
	th.Equal(t, "Update Feature affected", 1, result.RowsAffected())
	th.Equal(t, "Update Feature returned", 0, result.RowsReturned())
}

func testSubscriptionConfigurationUpdate(t *testing.T, q queries.SubscriptionConfigurationsInterface, model *m.SubscriptionConfiguration) {
	result, err := q.Update(model)

	if th.NoError(t, "Update Config error", err) {
		return
	}
	th.Equal(t, "Update Config affected", 1, result.RowsAffected())
	th.Equal(t, "Update Config returned", 0, result.RowsReturned())
}

func testSubscriptionPackageCount(t *testing.T, q queries.SubscriptionPackagesInterface, model *m.SubscriptionPackage) {
	result, err := q.Count(model)

	if th.NoError(t, "Count Package error", err) {
		return
	}
	th.Equal(t, "Count Package result", 1, result)
}

func testSubscriptionFeatureCount(t *testing.T, q queries.SubscriptionFeaturesInterface, model *m.SubscriptionFeature) {
	result, err := q.Count(model)

	th.NoError(t, "Count Feature error", err)
	th.Equal(t, "Count Feature result", 1, result)
}

func testSubscriptionConfigurationCount(t *testing.T, q queries.SubscriptionConfigurationsInterface, model *m.SubscriptionConfiguration) {
	result, err := q.Count(model)

	th.NoError(t, "Count Config error", err)
	th.Equal(t, "Count Config result", 1, result)
}

func testSubscriptionPackageSelect(t *testing.T, q queries.SubscriptionPackagesInterface, model *m.SubscriptionPackage) {
	result, err := q.Select(model, nil)

	th.NoError(t, "Select Package error", err)
	th.Equal(t, "Select Package result", 1, len(result))
}

func testSubscriptionFeatureSelect(t *testing.T, q queries.SubscriptionFeaturesInterface, model *m.SubscriptionFeature) {
	result, err := q.Select(model, nil)

	th.NoError(t, "Select Feature error", err)
	th.Equal(t, "Select Feature result", 1, len(result))
}

func testSubscriptionConfigurationSelect(t *testing.T, q queries.SubscriptionConfigurationsInterface, model *m.SubscriptionConfiguration) {
	result, err := q.Select(model, nil)

	th.NoError(t, "Select Config error", err)
	th.Equal(t, "Select Config result", 1, len(result))
}

func testSubscriptionFeatureLoad(t *testing.T, q queries.SubscriptionFeaturesInterface, model *m.SubscriptionFeature) {
	item := m.SubscriptionFeature{ID: model.ID}
	err := q.Load(&item)

	th.NoError(t, "Load Feature error", err)
	th.Equal(t, "Load Feature configurations", 1, len(item.Configurations))
}

func testSubscriptionPackageLoad(t *testing.T, q queries.SubscriptionPackagesInterface, model *m.SubscriptionPackage) {
	item := m.SubscriptionPackage{ID: model.ID}
	err := q.Load(&item)

	th.NoError(t, "Load Package error", err)
	th.Equal(t, "Load Package features", 1, len(item.Features))
}

func testSubscriptionPackageDelete(t *testing.T, q queries.SubscriptionPackagesInterface, model *m.SubscriptionPackage) {
	result, err := q.Delete(model)

	if th.NoError(t, "Delete Package error", err) {
		return
	}
	th.Equal(t, "Delete Package affected", 2, result.RowsAffected())
	th.Equal(t, "Delete Package returned", 0, result.RowsReturned())
}

func testSubscriptionFeatureDelete(t *testing.T, q queries.SubscriptionFeaturesInterface, model *m.SubscriptionFeature) {
	result, err := q.Delete(model)

	if th.NoError(t, "Delete Feature error", err) {
		return
	}
	th.Equal(t, "Delete Feature affected", 2, result.RowsAffected())
	th.Equal(t, "Delete Feature returned", 0, result.RowsReturned())
}

func testSubscriptionConfigDelete(t *testing.T, q queries.SubscriptionConfigurationsInterface, model *m.SubscriptionConfiguration) {
	result, err := q.Delete(model)

	if th.NoError(t, "Delete Config error", err) {
		return
	}
	th.Equal(t, "Delete Config affected", 0, result.RowsAffected())
	th.Equal(t, "Delete Config returned", 0, result.RowsReturned())
}
