package db

import (
	"LAPP_LF_MOM_BACKEND/conf"
	"LAPP_LF_MOM_BACKEND/utils"
	"context"
	"errors"
	"fmt"
	_ "github.com/denisenkom/go-mssqldb"
	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"log"
	"sync"
	"time"
)

var (
	Eloquent *xorm.EngineGroup
	elock    sync.Mutex
	mgoDb    *mongo.Client
	mlock    sync.Mutex
)

//初始化数据库
func InitDb() error {
	elock.Lock()
	defer elock.Unlock()

	//数据库信息
	dataDb := FindData()

	//从库集合
	var err error
	var master *xorm.Engine
	slaves := []*xorm.Engine{}
	for _, v := range dataDb {
		if v.Sourcetype == "Master" {
			switch v.DriverName {
			case "mssql":
				driveSource := fmt.Sprintf("server=%s;database=%s;user id=%s;password=%s;port=%d;encrypt=disable",
					v.Host, v.DbName, v.User, v.Pwd, v.Port)

				master, err = xorm.NewEngine("mssql", driveSource)
				if err != nil {
					fmt.Printf("err1 is %v", err)
					return err
				}
				if err = master.Ping(); err != nil {
					return err
				}
			case "mysql":
				driveSource := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8",
					v.User, v.Pwd, v.Host, v.Port, v.DbName)
				master, err = xorm.NewEngine("mysql", driveSource)
				if err != nil {
					fmt.Printf("err2 is %v", err)
					return err
				}
				if err = master.Ping(); err != nil {
					return err
				}

			}
			master.SetTZLocation(utils.TimezoneLocation)
			master.SetTZDatabase(utils.TimezoneLocation)
		} else if v.Sourcetype == "Slave"  {
			switch v.DriverName {
			case "mssql":
				driveSource := fmt.Sprintf("server=%s;database=%s;user id=%s;password=%s;port=%d;encrypt=disable",
					v.Host, v.DbName, v.User, v.Pwd, v.Port)

				slave, err := xorm.NewEngine("mssql", driveSource)
				if err != nil {
					fmt.Printf("err1 is %v", err)
					return err
				}
				if err = slave.Ping(); err != nil {
					return err
				}
				slaves = append(slaves, slave)
			case "mysql":
				driveSource := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8",
					v.User, v.Pwd, v.Host, v.Port, v.DbName)
				slave, err := xorm.NewEngine("mysql", driveSource)
				if err != nil {
					fmt.Printf("err2 is %v", err)
					return err
				}
				if err = slave.Ping(); err != nil {
					return err
				}
				slaves = append(slaves, slave)
			}
		}
	}
	Eloquent, err = xorm.NewEngineGroup(master, slaves)
	if err != nil {
		return err
	}
	Eloquent.ShowSQL(true)
	return nil
}

//初始化数据库
func InitTestDb() error {
	elock.Lock()
	defer elock.Unlock()

	//数据库信息
	dataDb := FindData()

	//从库集合
	var err error
	var testDB *xorm.Engine
	slaves := []*xorm.Engine{}
	for _, v := range dataDb {
		if v.Sourcetype == "Test" {
			switch v.DriverName {
			case "mssql":
				driveSource := fmt.Sprintf("server=%s;database=%s;user id=%s;password=%s;port=%d;encrypt=disable",
					v.Host, v.DbName, v.User, v.Pwd, v.Port)

				testDB, err = xorm.NewEngine("mssql", driveSource)
				if err != nil {
					fmt.Printf("err1 is %v", err)
					return err
				}
				if err = testDB.Ping(); err != nil {
					return err
				}
			case "mysql":
				driveSource := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8",
					v.User, v.Pwd, v.Host, v.Port, v.DbName)
				testDB, err = xorm.NewEngine("mysql", driveSource)
				if err != nil {
					fmt.Printf("err2 is %v", err)
					return err
				}
				if err = testDB.Ping(); err != nil {
					return err
				}

			}
		}
	}
	if testDB == nil {
		return errors.New("has no test db")
	}
	Eloquent, err = xorm.NewEngineGroup(testDB, slaves)
	if err != nil {
		return err
	}
	//Eloquent.ShowSQL(true)
	return nil
}

//创建mongoDb数据库链接
func MgoDb() *mongo.Client {
	//判断mgoDb是否存在
	if mgoDb != nil {
		return mgoDb
	}
	//创建之前会涉及并发，所以要加锁
	mlock.Lock()
	defer mlock.Unlock()
	//细节，防止多个请求锁住
	if mgoDb != nil {
		return mgoDb
	}
	//1.建立链接
	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
	client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://localhost:27017"))
	if err != nil {
		log.Fatal("dbhelper.MgoDb error= ", err)
		return nil
	} else {
		mgoDb = client
		return mgoDb
	}
}

//数据库
type Database struct {
	ID         string `bson:"id" json:"database-id"`                 //ID:uuid唯一字符串
	DbName     string `bson:"dbname" json:"database-dbname"`         //数据库名称
	DriverName string `bson:"drivername" json:"database-drivername"` //引擎类型
	Host       string `bson:"host" json:"database-host"`             //链接地址
	Port       int    `bson:"port" json:"database-port"`             //端口号
	User       string `bson:"user" json:"database-user"`             //用户名
	Pwd        string `bson:"pwd" json:"database-pwd"`               //密码
	Sourcetype string `bson:"sourcetype" json:"database-sourcetype"` //主库和从库
}

func FindData() []*Database {
	limit := int64(500)
	skip := int64(0)
	//1.初始化链接
	client := MgoDb()
	//2.选择数据库，数据表
	collect := client.Database(conf.DbConfig.Mongdbname).Collection("database")
	//var skip int64 = 0//从那个开始
	//var limit int64 = 2//炼制几个输出字段
	cursor, err := collect.Find(context.TODO(), bson.D{
	}, &options.FindOptions{
		Skip:  &skip,
		Limit: &limit,
		Sort:  bson.D{{"id", -1}},
	})
	fmt.Println(cursor)
	if err != nil {
		return nil
	}
	defer cursor.Close(context.TODO())
	//创建需要反序列化成什么样子的结构体对象
	records := make([]*Database, 0)
	for cursor.Next(context.TODO()) {
		record := &Database{}
		//反序列化
		err = cursor.Decode(record)
		if err != nil {
			fmt.Println(err)
			return nil
		}
		//追加
		records = append(records, record)
	}
	return records
}
