package db

import (
	"fmt"
	"os"
	"time"

	_ "github.com/go-sql-driver/mysql" //必须导入mysql驱动，否则会panic
	"xorm.io/xorm"
	"xorm.io/xorm/log"

	"applet/app/cfg"
	"applet/app/utils/logx"
)

var Db *xorm.Engine

// 根据DB配置文件初始化数据库
func InitDB(c *cfg.DBCfg) error {
	var (
		err error
		f   *os.File
	)
	//创建Orm引擎
	if Db, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", c.User, c.Psw, c.Host, c.Name)); err != nil {
		return err
	}
	Db.SetConnMaxLifetime(c.MaxLifetime * time.Second) //设置最长连接时间
	Db.SetMaxOpenConns(c.MaxOpenConns)                 //设置最大打开连接数
	Db.SetMaxIdleConns(c.MaxIdleConns)                 //设置连接池的空闲数大小
	if err = Db.Ping(); err != nil {                   //尝试ping数据库
		return err
	}
	if c.ShowLog { //根据配置文件设置日志
		Db.ShowSQL(true)        //设置是否打印sql
		Db.Logger().SetLevel(0) //设置日志等级
		//修改日志文件存放路径文件名是%s.log
		path := fmt.Sprintf(c.Path, c.Name)
		f, err = os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777)
		if err != nil {
			os.RemoveAll(c.Path)
			if f, err = os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777); err != nil {
				return err
			}
		}
		logger := log.NewSimpleLogger(f)
		logger.ShowSQL(true)
		Db.SetLogger(logger)
	}
	return nil
}

/********************************************* 公用方法 *********************************************/

// 数据批量插入
func DbInsertBatch(Db *xorm.Engine, m ...interface{}) error {
	if len(m) == 0 {
		return nil
	}
	id, err := Db.Insert(m...)
	if id == 0 || err != nil {
		return logx.Warn("cannot insert data :", err)
	}
	return nil
}

// QueryNativeString 查询原生sql
func QueryNativeString(Db *xorm.Engine, sql string, args ...interface{}) ([]map[string]string, error) {
	results, err := Db.SQL(sql, args...).QueryString()
	return results, err
}
func QueryNativeStringWithSess(sess *xorm.Session, sql string, args ...interface{}) ([]map[string]string, error) {
	results, err := sess.SQL(sql, args...).QueryString()
	return results, err
}

// UpdateComm common update
func UpdateComm(Db *xorm.Engine, id interface{}, model interface{}) (int64, error) {
	row, err := Db.ID(id).Update(model)
	return row, err
}

// InsertComm common insert
func InsertComm(Db *xorm.Engine, model interface{}) (int64, error) {
	row, err := Db.InsertOne(model)
	return row, err
}

// InsertCommWithSession common insert
func InsertCommWithSession(session *xorm.Session, model interface{}) (int64, error) {
	row, err := session.InsertOne(model)
	return row, err
}

// GetComm
// payload *model
// return *model,has,err
func GetComm(Db *xorm.Engine, model interface{}) (interface{}, bool, error) {
	has, err := Db.Get(model)
	if err != nil {
		_ = logx.Warn(err)
		return nil, false, err
	}
	return model, has, nil
}
