package models

import (
	"database/sql"
	"fmt"
	"reflect"

	_ "github.com/go-sql-driver/mysql"
)

type Gdo struct {
	conn *sql.DB
	arr  []interface{}
	stmt *sql.Stmt
}

func NewGdo(dbDatabase string) *Gdo {
	conn, err := sql.Open("mysql", "root:qq282246101@tcp(localhost:3306)/"+dbDatabase+"?charset=utf8")
	if err != nil {
		fmt.Println("连接数据库失败")
		conn.Close()
	}
	conn.SetConnMaxLifetime(100)
	conn.SetMaxOpenConns(30)
	g := &Gdo{}
	g.conn = conn
	return g
}
func (this *Gdo) Sql(sql string, arr ...interface{}) *Gdo {
	Stmt, err := this.conn.Prepare(sql)
	if err != nil {
		fmt.Printf("prepare sql failed, err:%v\n", err)
		this.conn.Close()
		return nil
	}
	this.stmt = Stmt
	this.arr = arr
	return this
}

// 查询成功 返回 true 返回值是 bool 手动写 指针取值
func (this *Gdo) Row(show ...interface{}) bool {
	row, _ := this.stmt.Query(this.arr...)
	defer row.Close()
	bl := row.Next()
	if bl == false {
		return false
	}
	row.Scan(show...)

	return true
}

// 返回*sql.Rows, error 手动写 指针取值
func (this *Gdo) RowS() (*sql.Rows, error) {
	rows, err := this.stmt.Query(this.arr...)
	return rows, err
}

// 失败返回空MAP 返回数据全部是string 数据库字段默认null即sql.NullString之类不能使用该方法
func (this *Gdo) Fetch() map[string]string {
	result := make(map[string]string)
	row, _ := this.stmt.Query(this.arr...)
	column, err := row.Columns()
	if err != nil {
		return result
	}
	values := make([][]byte, len(column))
	scans := make([]interface{}, len(column))
	for i, _ := range values {
		scans[i] = &values[i]
	}
	defer row.Close()
	bl := row.Next()
	if bl == false {
		return result
	}
	row.Scan(scans...)
	for i, v := range values {
		key := column[i]
		result[key] = string(v)
	}
	return result
}

// 失败返回空MAP 返回数据全部是string 数据库字段默认null即sql.NullString之类不能使用该方法
func (this *Gdo) FetchAll() map[int]map[string]string {
	result := make(map[int]map[string]string)
	rows, _ := this.stmt.Query(this.arr...)
	//得到 select 查询字段名与个数
	column, err := rows.Columns()
	if err != nil {
		return result
	}
	values := make([][]byte, len(column))
	//fmt.Println(values)
	scans := make([]interface{}, len(column))
	for i, _ := range values {
		scans[i] = &values[i]
	}
	//fmt.Println(scans)
	i := 0
	defer rows.Close()
	for rows.Next() {
		rows.Scan(scans...)
		row := make(map[string]string)
		for i, v := range values {
			key := column[i]
			row[key] = string(v)
		}
		result[i] = row
		i++
	}
	return result
}

// 失败返回0 成功返回 受影响行的个数
func (this *Gdo) Execute() int64 {
	crow, _ := this.stmt.Exec(this.arr...)
	re, err := crow.RowsAffected()
	if err != nil {
		return 0
	}
	return re
}

// 失败返回0 成功返回 行的id
func (this *Gdo) Insert() int64 {
	crow, _ := this.stmt.Exec(this.arr...)
	re, err := crow.LastInsertId()
	if err != nil {
		return 0
	}
	return re
}
func (this *Gdo) AutoInsert(table string, m map[string]interface{}) int64 {
	sql := "INSERT INTO " + table + " ("
	//(rid,user,password) VALUES (?,?,?)
	ik := ""
	iv := ""
	var mv []interface{}
	for k, v := range m {
		if ik == "" {
			ik = k + ","
		} else {
			ik = ik + k + ","
		}
		if iv == "" {
			iv = "?,"
		} else {
			iv = iv + "?" + ","
		}
		mv = append(mv, v)
	}
	ik = ik[0 : len(ik)-1]
	iv = iv[0 : len(iv)-1]
	sql = sql + ik + ") VALUES (" + iv + ")"
	return this.Sql(sql, mv...).Insert()
}
func StructToMap(obj interface{}) map[string]interface{} {
	t := reflect.TypeOf(obj)

	//获取到里面的值 一维数组 {100 beego gobee}
	v := reflect.ValueOf(obj)
	data := make(map[string]interface{})
	for i := 0; i < t.NumField(); i++ {
		//得到键名                //得到里面的值
		data[t.Field(i).Name] = v.Field(i)
	}
	return data
}
func StructToMapS(obj interface{}) map[string]string {
	t := reflect.TypeOf(obj)

	//获取到里面的值 一维数组 {100 beego gobee}
	v := reflect.ValueOf(obj)
	data := make(map[string]string)
	for i := 0; i < t.NumField(); i++ {
		//得到键名                //得到里面的值
		data[t.Field(i).Name] = v.Field(i).String()
	}
	return data
}
