package database

import (
	"fmt"
	"gitea.com/taozitaozi/gredis"
	"github.com/glebarez/sqlite"
	"github.com/go-redis/redis/v8"
	"github.com/loveuer/nfflow/internal/opt"
	"github.com/loveuer/nfflow/internal/util"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

func MustInitClient() {
	var (
		err error
	)

	// todo: 可以实现自己的 "Store" sql_db, like sqlite, postgresql
	if DB, err = initSql(); err != nil {
		panic(fmt.Errorf("database.MustInitClient: init sql err=%v", err))
	}

	// todo: 可以实现自己的 "Caches" 缓存, like redis
	if Cache, err = initCacher(); err != nil {
		panic(fmt.Errorf("database.MustInitCache: init cache err=%v", err))
	}
}

func initSql() (Store, error) {
	var (
		err    error
		client *gorm.DB
	)

	switch opt.Cfg.Database.Type {
	case "postgresql":
		dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=disable TimeZone=Asia/Shanghai",
			opt.Cfg.Database.Host, opt.Cfg.Database.Username, opt.Cfg.Database.Password, opt.Cfg.Database.DB, opt.Cfg.Database.Port)
		if client, err = gorm.Open(postgres.Open(dsn)); err != nil {
			return nil, err
		}
	case "mysql":
		dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
			opt.Cfg.Database.Username, opt.Cfg.Database.Password, opt.Cfg.Database.Host, opt.Cfg.Database.Port, opt.Cfg.Database.DB)
		if client, err = gorm.Open(mysql.Open(dsn)); err != nil {
			return nil, err
		}
	case "sqlite":
		if client, err = gorm.Open(sqlite.Open(opt.Cfg.Database.Path)); err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("unsupportted databsae type=%s", opt.Cfg.Database.Type)
	}

	return &_db{client: client}, nil
}

func initCacher() (Caches, error) {
	var (
		err error
	)

	switch opt.Cfg.Cache.Type {
	case "redis":
		var rc *redis.Client
		rc = redis.NewClient(&redis.Options{
			Addr:     fmt.Sprintf("%s:%d", opt.Cfg.Cache.Host, opt.Cfg.Cache.Port),
			Username: opt.Cfg.Cache.Username,
			Password: opt.Cfg.Cache.Password,
		})

		if err = rc.Ping(util.Timeout(5)).Err(); err != nil {
			return nil, fmt.Errorf("redis ping err=%v", err)
		}

		return &_redis{client: rc}, nil
	case "memory":
		var mc *gredis.Gredis
		mc = gredis.NewGredis(-1)

		return &_mem{client: mc}, nil
	default:
		return nil, fmt.Errorf("unsupportted cache type=%s", opt.Cfg.Cache.Type)
	}

}