package store

import (
	"database/sql"

	sq "github.com/Masterminds/squirrel"

	"git.ctrlz.es/mgdelacroix/craban/model"
)

var userColumns = []string{"id", "name", "mail", "username", "password"}

type UserStore struct {
	Conn *sql.DB
}

func NewUserStore(s *Store) *UserStore {
	return &UserStore{Conn: s.Conn}
}

func (us *UserStore) Q() sq.StatementBuilderType {
	return sq.StatementBuilder.RunWith(us.Conn)
}

func (us *UserStore) usersFromRows(rows *sql.Rows) ([]*model.User, error) {
	users := []*model.User{}

	for rows.Next() {
		var user model.User

		err := rows.Scan(
			&user.ID,
			&user.Name,
			&user.Mail,
			&user.Username,
			&user.Password,
		)
		if err != nil {
			return nil, err
		}

		users = append(users, &user)
	}

	return users, nil
}

func (us *UserStore) GetByID(id int) (*model.User, error) {
	query := us.Q().Select(userColumns...).
		From("users").
		Where(sq.Eq{"id": id})

	rows, err := query.Query()
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	users, err := us.usersFromRows(rows)
	if err != nil {
		return nil, err
	}

	if len(users) == 0 {
		return nil, sql.ErrNoRows
	}

	return users[0], nil
}

func (us *UserStore) Create(user *model.User) (*model.User, error) {
	query := us.Q().Insert("users").
		Columns(userColumns[1:]...).
		Values(user.Name, user.Mail, user.Username, user.Password)

	res, err := query.Exec()
	if err != nil {
		return nil, err
	}

	id, err := res.LastInsertId()
	if err != nil {
		return nil, err
	}

	return us.GetByID(int(id))
}
