package core

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/uptrace/bun"
	"github.com/uptrace/bun/dialect/pgdialect"
	"github.com/uptrace/bun/driver/pgdriver"

	m "fr.latosa-escrima/core/models"
)

var DB *bun.DB

type DSN struct {
	Hostname string
	Port     string
	DBName   string
	User     string
	Password string
}

func (dsn *DSN) ToString() string {
	return fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable", dsn.User, dsn.Password, dsn.Hostname, dsn.Port, dsn.DBName)
}

func InitDatabase(dsn DSN) (*bun.DB, error) {
	sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn.ToString())))
	db := bun.NewDB(sqldb, pgdialect.New())

	ctx := context.Background()

	_, err := db.ExecContext(ctx, "CREATE EXTENSION IF NOT EXISTS pgcrypto;")
	if err != nil {
		return nil, err
	}
	db.RegisterModel((*m.EventToUser)(nil))
	db.RegisterModel((*m.PermissionToRole)(nil))
	db.RegisterModel((*m.UserToRole)(nil))
	_, err = db.NewCreateTable().
		Model((*m.User)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.Event)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.EventToUser)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.Blog)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.WebsiteSettings)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.Media)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.Shortcode)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.Role)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.Permission)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.PermissionToRole)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.UserToRole)(nil)).IfNotExists().Exec(ctx)

	_, err = db.NewCreateTable().
		Model((*m.Location)(nil)).IfNotExists().Exec(ctx)

	if err != nil {
		return nil, err
	}

	perms := GetAllPermissions()
	err = perms.InsertAll(db, ctx)
	if err != nil {
		return nil, err
	}

	return db, nil
}
