package holo

import (
	"database/sql"
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"time"

	"github.com/lib/pq"
	_ "github.com/lib/pq"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/log"
	"gitlab.alibaba-inc.com/pai_biz_arch/pairec/recconf"
)

func init() {
	sql.Register("hologres", &HologresDriver{})
}

type HologresDriver struct {
	driver pq.Driver
}

func (d HologresDriver) Open(name string) (driver.Conn, error) {
	conn, err := d.driver.Open(name)
	if err != nil {
		return nil, err
	}

	if stmt, err := conn.Prepare("set statement_timeout = 500"); err == nil {
		stmt.Exec(nil)
		stmt.Close()
	}
	return conn, err
}

type Postgres struct {
	DSN  string
	DB   *sql.DB
	Name string
}

var postgresqlInstances = make(map[string]*Postgres)

func GetPostgres(name string) (*Postgres, error) {
	if _, ok := postgresqlInstances[name]; !ok {
		return nil, fmt.Errorf("Postgres not found, name:%s", name)
	}

	return postgresqlInstances[name], nil
}
func (m *Postgres) Init() error {
	db, err := sql.Open("hologres", m.DSN)
	if err != nil {
		return err
	}

	db.SetConnMaxLifetime(180 * time.Minute)
	db.SetMaxIdleConns(100)
	db.SetMaxOpenConns(200)

	m.DB = db
	err = m.DB.Ping()
	go m.loopDBStats()
	return err
}
func (m *Postgres) loopDBStats() {
	for {
		stat := m.DB.Stats()
		j, _ := json.Marshal(stat)
		log.Info(fmt.Sprintf("event=dbstat\tname=%s\tmsg=%s", m.Name, string(j)))

		time.Sleep(5 * time.Second)
	}
}
func Load(config *recconf.RecommendConfig) {
	for name, conf := range config.HologresConfs {
		m := &Postgres{
			DSN:  conf.DSN,
			Name: name,
		}
		err := m.Init()
		if err != nil {
			panic(err)
		}
		postgresqlInstances[name] = m
	}
}
