package main

import (
	"log"

	"github.com/ory/dockertest/v3"
	"github.com/ory/dockertest/v3/docker"
	"github.com/tidbcloud/ecosystem-service/internal/storage/db/git"
	"github.com/tidbcloud/ecosystem-service/internal/storage/db/vercel"
	"github.com/tidbcloud/ecosystem-service/internal/storage/migrate"
	"github.com/tidbcloud/ecosystem-service/internal/storage/migrate/record"
	_ "github.com/tidbcloud/ecosystem-service/internal/storage/migrate/record"
	"github.com/tidbcloud/pkgv2/gormutil"
	"gorm.io/gorm"
)

var MigrateTables = append(git.MigrateTables, vercel.MigrateTables...)

// Do not use os.Exit() or log.Fatal() after allocating resource, otherwise the defer function will not be executed, the docker resource will not be released.
func main() {
	// uses a sensible default on windows (tcp/http) and linux/osx (socket)
	pool, err := dockertest.NewPool("")
	if err != nil {
		log.Fatalf("Could not connect to docker: %s", err)
	}

	// pulls an image, creates a container based on it and runs it
	resource, err := pool.RunWithOptions(&dockertest.RunOptions{
		Repository:   "mysql",
		Tag:          "5.7",
		Env:          []string{"MYSQL_ROOT_PASSWORD=secret"},
		ExposedPorts: []string{"50505"},
		PortBindings: map[docker.Port][]docker.PortBinding{
			"3306/tcp": {{HostIP: "127.0.0.1", HostPort: "60606"}},
		},
		Platform: "linux/x86_64",
	}, func(config *docker.HostConfig) {
		config.AutoRemove = true
		config.RestartPolicy = docker.RestartPolicy{
			Name: "no",
		}
	})

	if err != nil {
		log.Fatalf("Could not start resource: %s", err)
	}

	connCfg := gormutil.Config{
		User:              "root",
		Host:              "127.0.0.1",
		Database:          "mysql",
		Password:          "secret",
		Port:              60606,
		EnableDetailedLog: true,
		LogLevel:          "info",
	}

	var db *gorm.DB
	// exponential backoff-retry, because the application in the container might not be ready to accept connections yet
	if err := pool.Retry(func() error {
		var err error
		database, err := gormutil.Connect(connCfg)
		if err != nil {
			return err
		}

		db = database

		return nil
	}); err != nil {
		log.Panicf("Could not connect to database: %s", err)
	}

	defer func() {
		if err := pool.Purge(resource); err != nil {
			log.Fatalf("Could not purge resource: %s", err)
		}
	}()

	migrator := migrate.NewMigrator(db)
	record.InitRecorderExecutor(migrator)
	// Initial with old table schema
	if err := migrator.RunMigrate(); err != nil {
		log.Panicf("Could not run previous migrates: %s", err)
	}

	// Print DDL SQL
	if err := migrate.GormAutoMigrateAndPrint(db, MigrateTables); err != nil {
		log.Panicf("Could not run current migrate: %s", err)
	}
}
