package mysql

import (
	"database/sql"
	"time"

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

type (
	MysqlStorage struct {
		db    *sql.DB
		state map[string]*steward.State

		importStmt    *sql.Stmt
		saveStateStmt *sql.Stmt
		loadStateStmt *sql.Stmt
	}
)

const (
	importQuery    = "replace into commits (sha1, author, repo, ts) values (?, ?, ?, ?)"
	saveStateQuery = "replace into state (repo, sha1, ts) values (?, ?, ?)"
	loadStateQuery = "select repo, sha1, ts from state"
)

func New() *MysqlStorage {
	var (
		s = &MysqlStorage{
			state: map[string]*steward.State{},
		}
		err error
	)

	if s.db, err = sql.Open("mysql", "root@/steward?parseTime=true"); err != nil {
		panic(err)
	}
	if s.importStmt, err = s.db.Prepare(importQuery); err != nil {
		panic(err)
	}
	if s.saveStateStmt, err = s.db.Prepare(saveStateQuery); err != nil {
		panic(err)
	}

	s.loadGlobalState()

	return s
}

func (ms *MysqlStorage) Import(repo string, hist map[string]*steward.Commit) {
	var (
		lastTimestamp *time.Time
		lastSha1      string
	)

	for sha1, c := range hist {
		if _, err := ms.importStmt.Exec(sha1, c.Author, repo, c.Timestamp); err != nil {
			panic(err)
		}
		if lastTimestamp == nil || lastTimestamp.After(c.Timestamp) {
			lastTimestamp = &c.Timestamp
			lastSha1 = sha1
		}
	}

	ms.saveRepoState(repo, lastSha1, *lastTimestamp)
}

func (ms *MysqlStorage) saveRepoState(repo string, sha1 string, ts time.Time) {
	if _, err := ms.saveStateStmt.Exec(repo, sha1, ts); err != nil {
		panic(err)
	}
}

func (ms *MysqlStorage) loadGlobalState() {
	var (
		repo string
		sha1 string
		ts   time.Time
	)

	rows, err := ms.db.Query(loadStateQuery)
	if err != nil {
		panic(err)
	}
	for rows.Next() {
		if err := rows.Scan(&repo, &sha1, &ts); err != nil {
			panic(err)
		}
		ms.state[repo] = &steward.State{
			Sha1:      sha1,
			Timestamp: ts,
		}
	}
}