package sqlAsyncMgr

import (
	"fmt"
	"time"

	"framework/goroutineMgr"
	"github.com/jinzhu/gorm"
	"goutil/logUtil"
)

const (
	// 同步多少次打印待同步sql数量
	LogSyncCount = 1000
)

// sql同步的worker
type SqlAsyncWorker struct {
	// 工作者Id
	Id int32

	// 是否停止工作
	IsTop bool

	// 当前同步的条数
	CurSyncCount int32

	// 待执行对象
	cachModel *SqlAsyncListModel

	// 刷新到时候的回调方法
	flushDbCallBack func(*SqlAsyncItemModel)

	// 日志处理方法
	logAction func(logUtil.LogType, string)

	// 获取同步标识
	getSyncName func() string

	// 数据库驱动
	db *gorm.DB

	tempCount int
}

// newSqlAsyncWorker  创建新SqlAsyncWorker对象
func newSqlAsyncWorker(_id int32, _flushCallBack func(*SqlAsyncItemModel), _logAction func(logUtil.LogType, string), _getSyncName func() string, _db *gorm.DB) *SqlAsyncWorker {
	return &SqlAsyncWorker{
		Id:              _id,
		cachModel:       newSqlAsyncListModel(),
		flushDbCallBack: _flushCallBack,
		logAction:       _logAction,
		getSyncName:     _getSyncName,
		db:              _db,
	}
}

// Start 启动工作
func (this *SqlAsyncWorker) Start() {
	go this.handler()
}

// Stop 停止工作
func (this *SqlAsyncWorker) Stop() []*SqlAsyncItemModel {
	this.IsTop = true

	return this.cachModel.GetAllSqlModel()
}

// Add 添加执行的sql对象
func (this *SqlAsyncWorker) Add(item *SqlAsyncItemModel) {
	if this.IsTop {
		return
	}

	this.cachModel.Add(item)
}

// WaitSqlCount 获取待同步的sql数量
func (this *SqlAsyncWorker) WaitSqlCount() int32 {
	return this.cachModel.SqlCount()
}

// FlushDB 刷新到DB
func (this *SqlAsyncWorker) handler() {
	// 处理goroutine数量
	goroutineName := fmt.Sprintf("%s-%v", this.getSyncName(), this.Id)
	goroutineMgr.Monitor(goroutineName)
	defer goroutineMgr.ReleaseMonitor(goroutineName)

	for {
		if this.IsTop {
			this.logAction(logUtil.Debug, fmt.Sprintf("sql异步线程停止工作 name=%s", goroutineName))
			return
		}

		if this.flushItem() == false {
			time.Sleep(time.Millisecond * 100)
		}
	}
}

// flushItem 刷新到DB
func (this *SqlAsyncWorker) flushItem() bool {
	defer func() {
		if r := recover(); r != nil {
			this.logAction(logUtil.Error, fmt.Sprintf("flushItem err:%s", r))
		}
	}()

	// 获取同步对象
	item, exists := this.cachModel.GetItem()
	if exists == false {
		return false
	}

	this.tempCount = this.tempCount + 1

	// 写入数据库
	for i := 0; i < 3; i++ {
		err := this.db.Exec(item.Sql).Error
		if err == nil {
			break
		}

		this.logAction(logUtil.Error, fmt.Sprintf("写入数据库出现错误 sql:%s  err:%s", item.Sql, err.Error()))
	}

	// 移除缓存
	this.cachModel.RemoveFirst()

	// 减少统计
	this.flushDbCallBack(item)

	// 统计当前待同步数量
	this.CurSyncCount = this.CurSyncCount + 1
	if this.CurSyncCount%LogSyncCount == 0 {
		this.logAction(logUtil.Debug, fmt.Sprintf("当前待同步的sql数量为:%v Name:%s  id:%v", this.cachModel.SqlCount(), this.getSyncName(), this.Id))
		this.CurSyncCount = 0
	}

	return true
}
