package db_test

import (
	"reflect"
	"testing"

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

var instance db.Migrator

type TestTable struct {
	ID   int64
	Name string
	dbbasemodel.DBModelBase
}

type TestTable2 struct {
	//lint:ignore U1000 metadata for go-pg to use alternative sql table name
	tableName struct{} `pg:"test_tables,alias:test_alias"`
	ID        int64
	Name      string `pg:",unique"`
	Address   string `pg:",unique:group_name"`
	City      string `pg:",unique:group_name"`
	dbbasemodel.DBModelBase
}

type NonExistingTable struct {
	ID int64
}

func TestMigratorIntegration(t *testing.T) {
	t.Skip()
	setupMigrator()
	migratorTableName(t)
	migratorTableExists(t)
	migrateTableFields(t)
	migrateTable(t)
}

func setupMigrator() {
	instance = db.Migrator{
		DB:     db.GetDefaultConn(),
		DryRun: false,
	}
	instance.DB.AddQueryHook(db.SQLLogger{})
}

func migratorTableName(t *testing.T) {

	tablename := instance.GetTableName((*TestTable)(nil))
	if tablename != "test_tables" {
		t.Error("Table name does not match")
	}

	tablename = instance.GetTableName((*TestTable2)(nil))
	if tablename != "test_tables" {
		t.Error("Table name does not match")
	}
}

func migrateTableFields(t *testing.T) {
	type TestCase struct {
		fieldName string
		fieldType string
	}
	tests := []TestCase{
		{
			fieldName: "id",
			fieldType: "bigint",
		},
		{
			fieldName: "name",
			fieldType: "text",
		},
		{
			fieldName: "created_at",
			fieldType: "timestamptz",
		},
		{
			fieldName: "updated_at",
			fieldType: "timestamptz",
		},
	}

	columns := instance.GetFields(reflect.TypeOf((*TestTable)(nil)))
	if len(columns) != 4 {
		t.Error("Incorrect number of columns")
	}

test:
	for _, test := range tests {
		for _, col := range columns {
			if col.ColumnName == test.fieldName {
				if col.DataType == test.fieldType {
					continue test
				} else {
					t.Errorf("%s type %s is not %s", test.fieldName, col.DataType, test.fieldType)
					continue test
				}
			}
		}
		t.Errorf("%s not found", test.fieldName)
	}
}

func migrateTable(t *testing.T) {
	err := instance.Check((*TestTable)(nil))
	if err != nil {
		t.Error(err)
	}

	err = instance.Check((*TestTable2)(nil))
	if err != nil {
		t.Error(err)
	}

	err = instance.Check((*TestTable)(nil))
	if err != nil {
		t.Error(err)
	}

	err = instance.DropTable((*TestTable)(nil))
	if err != nil {
		t.Error(err)
	}
}

func migratorTableExists(t *testing.T) {
	err := instance.TableExists((*NonExistingTable)(nil))
	if err == nil {
		t.Errorf("Table should not exist %v", err)
	}

	err = instance.TableExists((*common.Car)(nil))
	if err != nil {
		t.Errorf("Table should exist %v", err)
	}
}

func BenchmarkMigrator(b *testing.B) {
	migrator := db.Migrator{
		DB:     db.GetDefaultConn(),
		DryRun: false,
	}

	for n := 0; n < b.N; n++ {
		migrator.Check((*TestTable2)(nil))
	}
}
