package model

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

type ProcessLog struct {
	Model
}

type ProcessLogRow struct {
	Id              int64
	RedisId         int64
	RedisAddress    string
	RedisRemark     string
	ProcessTime     int64
	MaxMemoryBefore int64
	MaxMemoryAfter  int64
}

func NewProcessLog(db *sql.DB) *ProcessLog {
	return &ProcessLog{
		Model{
			db: db,
		},
	}
}

func (m *ProcessLog) Add(row *ProcessLogRow) (int64, error) {
	if row.RedisId <= 0 {
		return 0, errors.New("Redis的ID必须是正整数")
	}
	if row.ProcessTime <= 0 {
		row.ProcessTime = time.Now().Unix()
	}
	ret, err := m.db.Exec("INSERT INTO processlog(redis_id,process_time,maxmemory_before,maxmemory_after) VALUES(?,?,?,?)", row.RedisId, row.ProcessTime, row.MaxMemoryBefore, row.MaxMemoryAfter)
	if err != nil {
		return 0, err
	} else {
		return ret.LastInsertId()
	}
}

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

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

func (m *ProcessLog) GetList(redisId int64, offset int64, limit int64, orderDesc bool) ([]*ProcessLogRow, 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 processlog.id,processlog.redis_id,processlog.process_time,processlog.maxmemory_before,processlog.maxmemory_after,rediscfg.address,rediscfg.remark FROM processlog INNER JOIN rediscfg ON processlog.redis_id=rediscfg.id ORDER BY processlog.id %s LIMIT ?,?", orderDir)
			ret, err = m.db.Query(sql, offset, limit)
		} else {
			sql := fmt.Sprintf("SELECT processlog.id,processlog.redis_id,processlog.process_time,processlog.maxmemory_before,processlog.maxmemory_after,rediscfg.address,rediscfg.remark FROM processlog INNER JOIN rediscfg ON processlog.redis_id=rediscfg.id ORDER BY processlog.id %s", orderDir)
			ret, err = m.db.Query(sql)
		}

	} else {
		if limit > 0 {
			sql := fmt.Sprintf("SELECT processlog.id,processlog.redis_id,processlog.process_time,processlog.maxmemory_before,processlog.maxmemory_after,rediscfg.address,rediscfg.remark FROM processlog INNER JOIN rediscfg ON processlog.redis_id=rediscfg.id WHERE processlog.redis_id=? ORDER BY processlog.id %s LIMIT ?,?", orderDir)
			ret, err = m.db.Query(sql, redisId, offset, limit)
		} else {
			sql := fmt.Sprintf("SELECT processlog.id,processlog.redis_id,processlog.process_time,processlog.maxmemory_before,processlog.maxmemory_after,rediscfg.address,rediscfg.remark FROM processlog INNER JOIN rediscfg ON processlog.redis_id=rediscfg.id WHERE processlog.redis_id=? ORDER BY processlog.id %s", orderDir)
			ret, err = m.db.Query(sql, redisId)
		}
	}
	if err != nil {
		return nil, err
	} else {
		rows := make([]*ProcessLogRow, 0)
		for ret.Next() {
			row := ProcessLogRow{}
			err = ret.Scan(&row.Id, &row.RedisId, &row.ProcessTime, &row.MaxMemoryBefore, &row.MaxMemoryAfter, &row.RedisAddress, &row.RedisRemark)
			if err != nil {
				continue
			}
			rows = append(rows, &row)
		}
		return rows, nil
	}
}
