package storage

import (
	"database/sql"
	"time"

	_ "github.com/mattn/go-sqlite3"
)

// DB wraps sql.DB
type DB struct {
	conn *sql.DB
}

// Default is the package-level DB used by handlers
var Default *DB

// Init opens the sqlite database at path and ensures the table exists
func Init(path string) (*DB, error) {
	conn, err := sql.Open("sqlite3", path)
	if err != nil {
		return nil, err
	}
	// set reasonable pragmas
	if _, err := conn.Exec("PRAGMA journal_mode=WAL;"); err != nil {
		// ignore
	}
	schema := `CREATE TABLE IF NOT EXISTS messages (
        message TEXT NOT NULL,
        timestamp TEXT NOT NULL
    );`
	if _, err := conn.Exec(schema); err != nil {
		conn.Close()
		return nil, err
	}
	return &DB{conn: conn}, nil
}

// SetDefault sets the package default DB
func SetDefault(d *DB) {
	Default = d
}

// Close closes the underlying connection
func (d *DB) Close() error {
	if d == nil || d.conn == nil {
		return nil
	}
	return d.conn.Close()
}

// InsertMessage inserts a message with timestamp into the DB
func (d *DB) InsertMessage(msg string, ts time.Time) error {
	if d == nil || d.conn == nil {
		return nil
	}
	_, err := d.conn.Exec("INSERT INTO messages(message, timestamp) VALUES(?, ?)", msg, ts.Format(time.RFC3339))
	return err
}

// Message is the returned message shape
type Message struct {
	Message   string `json:"message"`
	Timestamp string `json:"timestamp"`
}

// QueryMessages returns messages ordered by newest first
func (d *DB) QueryMessages(limit, offset int) ([]Message, error) {
	if d == nil || d.conn == nil {
		return nil, nil
	}
	rows, err := d.conn.Query("SELECT message, timestamp FROM messages ORDER BY rowid DESC LIMIT ? OFFSET ?", limit, offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	res := []Message{}
	for rows.Next() {
		var m Message
		if err := rows.Scan(&m.Message, &m.Timestamp); err != nil {
			return nil, err
		}
		res = append(res, m)
	}
	return res, nil
}
