package model

import (
	"database/sql"
	"errors"
	"fmt"
	"time"
)

type MonitorLog struct {
	Model
}

type MonitorLogRow struct {
	Id           int64
	RedisId      int64
	RedisAddress string
	RedisRemark  string
	LogTime      int64
	QueryStatus  bool
	FailedCount  int64
	UsedMemory   int64
	MaxMemory    int64
	SystemMemory int64
	Connection   int64
	QPS          int64
	EvictedKeys  int64
	EviIncreased int64
	LastMailTime int64
}

func NewMonitorLog(db *sql.DB) *MonitorLog {
	return &MonitorLog{
		Model{
			db: db,
		},
	}
}

func (m *MonitorLog) Add(row *MonitorLogRow) (int64, error) {
	if row.RedisId <= 0 {
		return 0, errors.New("Redis的ID必须是正整数")
	}
	if row.LogTime <= 0 {
		row.LogTime = time.Now().Unix()
	}
	queryStatusInt := 0
	if row.QueryStatus {
		queryStatusInt = 1
	}
	ret, err := m.db.Exec(`INSERT INTO monitorlog(redis_id,log_time,query_status,failed_count,used_memory,max_memory,system_memory,connection,qps,evicted_keys,evi_increased) VALUES(?,?,?,?,?,?,?,?,?,?,?)`,
		row.RedisId,
		row.LogTime,
		queryStatusInt,
		row.FailedCount,
		row.UsedMemory,
		row.MaxMemory,
		row.SystemMemory,
		row.Connection,
		row.QPS,
		row.EvictedKeys,
		row.EviIncreased,
	)
	if err != nil {
		return 0, err
	} else {
		return ret.LastInsertId()
	}
}

func (m *MonitorLog) CleanUntil(until int64) (int64, error) {
	ret, err := m.db.Exec("DELETE FROM monitorlog WHERE log_time<?", until)
	if err != nil {
		return 0, err
	} else {
		return ret.RowsAffected()
	}
}

func (m *MonitorLog) Count(redisId int64) (int64, error) {
	var (
		row *sql.Row
		cnt int64
	)
	if redisId == 0 {
		row = m.db.QueryRow("SELECT COUNT(*) FROM monitorlog")
	} else {
		row = m.db.QueryRow("SELECT COUNT(*) FROM monitorlog WHERE redis_id=?", redisId)
	}
	if err := row.Scan(&cnt); err != nil {
		return 0, err
	} else {
		return cnt, nil
	}
}

func (m *MonitorLog) GetList(redisId int64, offset int64, limit int64, orderDesc bool) ([]*MonitorLogRow, error) {
	var (
		orderDir string
		ret      *sql.Rows
		err      error
	)
	if orderDesc {
		orderDir = "DESC"
	} else {
		orderDir = "ASC"
	}
	if redisId == 0 {
		if limit > 0 {
			sql := fmt.Sprintf(`SELECT
						monitorlog.id,
						monitorlog.redis_id,
						monitorlog.log_time,
						monitorlog.query_status,
						monitorlog.failed_count,
						monitorlog.used_memory,
						monitorlog.max_memory,
						monitorlog.system_memory,
						monitorlog.connection,
						monitorlog.qps,
						monitorlog.evicted_keys,
						monitorlog.evi_increased,
						rediscfg.address,
						rediscfg.remark
					FROM monitorlog INNER JOIN rediscfg ON monitorlog.redis_id=rediscfg.id ORDER BY monitorlog.id %s LIMIT ?,?`,
				orderDir,
			)
			ret, err = m.db.Query(sql, offset, limit)
		} else {
			sql := fmt.Sprintf(`SELECT
						monitorlog.id,
						monitorlog.redis_id,
						monitorlog.log_time,
						monitorlog.query_status,
						monitorlog.failed_count,
						monitorlog.used_memory,
						monitorlog.max_memory,
						monitorlog.system_memory,
						monitorlog.connection,
						monitorlog.qps,
						monitorlog.evicted_keys,
						monitorlog.evi_increased,
						rediscfg.address,
						rediscfg.remark
					FROM monitorlog INNER JOIN rediscfg ON monitorlog.redis_id=rediscfg.id ORDER BY monitorlog.id %s`,
				orderDir,
			)
			ret, err = m.db.Query(sql)
		}

	} else {
		if limit > 0 {
			sql := fmt.Sprintf(`SELECT
						monitorlog.id,
						monitorlog.redis_id,
						monitorlog.log_time,
						monitorlog.query_status,
						monitorlog.failed_count,
						monitorlog.used_memory,
						monitorlog.max_memory,
						monitorlog.system_memory,
						monitorlog.connection,
						monitorlog.qps,
						monitorlog.evicted_keys,
						monitorlog.evi_increased,
						rediscfg.address,
						rediscfg.remark
					FROM monitorlog INNER JOIN rediscfg ON monitorlog.redis_id=rediscfg.id WHERE monitorlog.redis_id=? ORDER BY monitorlog.id %s LIMIT ?,?`,
				orderDir,
			)
			ret, err = m.db.Query(sql, redisId, offset, limit)
		} else {
			sql := fmt.Sprintf(`SELECT
						monitorlog.id,
						monitorlog.redis_id,
						monitorlog.log_time,
						monitorlog.query_status,
						monitorlog.failed_count,
						monitorlog.used_memory,
						monitorlog.max_memory,
						monitorlog.system_memory,
						monitorlog.connection,
						monitorlog.qps,
						monitorlog.evicted_keys,
						monitorlog.evi_increased,
						rediscfg.address,
						rediscfg.remark
					FROM monitorlog INNER JOIN rediscfg ON monitorlog.redis_id=rediscfg.id WHERE monitorlog.redis_id=? ORDER BY monitorlog.id %s`,
				orderDir,
			)
			ret, err = m.db.Query(sql, redisId)
		}
	}
	if err != nil {
		return nil, err
	} else {
		rows := make([]*MonitorLogRow, 0)
		for ret.Next() {
			row := MonitorLogRow{}
			err = ret.Scan(
				&row.Id,
				&row.RedisId,
				&row.LogTime,
				&row.QueryStatus,
				&row.FailedCount,
				&row.UsedMemory,
				&row.MaxMemory,
				&row.SystemMemory,
				&row.Connection,
				&row.QPS,
				&row.EvictedKeys,
				&row.EviIncreased,
				&row.RedisAddress,
				&row.RedisRemark,
			)
			if err != nil {
				continue
			}
			rows = append(rows, &row)
		}
		return rows, nil
	}
}
