package db

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	newDb "music-server/db"
	"os"

	"github.com/golang-migrate/migrate/v4"
	"github.com/golang-migrate/migrate/v4/database/postgres"
	_ "github.com/golang-migrate/migrate/v4/database/postgres"
	_ "github.com/golang-migrate/migrate/v4/source/file"
	"github.com/golang-migrate/migrate/v4/source/iofs"
	"github.com/jackc/pgx/v5/pgxpool"
	_ "github.com/lib/pq"
)

var Dbpool *pgxpool.Pool
var Ctx = context.Background()

func InitDB(host string, port int, user string, password string, dbname string) {

	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, port, user, password, dbname)

	fmt.Println(psqlInfo)

	var err error
	Dbpool, err = pgxpool.New(Ctx, psqlInfo)
	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
		os.Exit(1)
	}

	var success string
	err = Dbpool.QueryRow(Ctx, "select 'Successfully connected!'").Scan(&success)
	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
		os.Exit(1)
	}
	Testf()
	fmt.Println(success)
}

func CloseDb() {
	Dbpool.Close()
}

func Testf() {
	rows, dbErr := Dbpool.Query(Ctx, "select game_name from game")
	if dbErr != nil {
		_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", dbErr)
		os.Exit(1)
	}
	for rows.Next() {
		var gameName string
		dbErr = rows.Scan(&gameName)
		if dbErr != nil {
			_, _ = fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", dbErr)
		}
		_, _ = fmt.Fprintf(os.Stderr, "%v\n", gameName)
	}
}

func resetGameIdSeq() {
	_, err := Dbpool.Query(Ctx, "SELECT setval('game_id_seq', (SELECT MAX(id) FROM game)+1);")
	if err != nil {
		_, _ = fmt.Fprintf(os.Stderr, "Exec failed: %v\n", err)
	}
}

func Migrate_db(host string, port int, user string, password string, dbname string) {
	migrationInfo := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable",
		user, password, host, port, dbname)

	fmt.Println("Migration Info: ", migrationInfo)

	db, err := sql.Open("postgres", migrationInfo)
	if err != nil {
		log.Println(err)
	}
	driver, err := postgres.WithInstance(db, &postgres.Config{})
	if err != nil {
		log.Println(err)
	}
	files, err := iofs.New(newDb.MigrationsFs, "migrations")
	if err != nil {
		log.Fatal(err)
	}
	m, err := migrate.NewWithInstance("iofs", files, "postgres", driver)
	if err != nil {
		log.Fatal(err)
	}
	/*m, err := migrate.NewWithDatabaseInstance(
		"file://./db/migrations/",
		"postgres", driver)
	if err != nil {
		log.Println(err)
	}*/

	version, _, err := m.Version()
	if err != nil {
		log.Println("Migration version err: ", err)
	}

	fmt.Println("Migration version before: ", version)

	err = m.Force(1)
	//err = m.Up() // or m.Steps(2) if you want to explicitly set the number of migrations to run
	if err != nil {
		log.Println("Force err: ", err)
	}

	err = m.Migrate(2)
	//err = m.Up() // or m.Steps(2) if you want to explicitly set the number of migrations to run
	if err != nil {
		log.Println("Migration err: ", err)
	}

	versionAfter, _, err := m.Version()
	if err != nil {
		log.Println("Migration version err: ", err)
	}

	fmt.Println("Migration version after: ", versionAfter)

	fmt.Println("Migration done")

	db.Close()
}
