# libraries
bcrypt = (require 'bcrypt')
sqlite3 = (require 'sqlite3').verbose()

# bruteforce countermeasure
saltRounds = 13

FFTCGDB = (filename) ->
  @filename = filename

  @db = new sqlite3.Database @filename, (err) ->
    if err
      console.error err.message

  @db.run """
    CREATE TABLE IF NOT EXISTS users (
      login text NOT NULL COLLATE NOCASE,
      pwdhash text NOT NULL,
      session text,
      UNIQUE(login)
    );
  """
  console.log "[FFTCGDB] Connected to '#{@filename}'"
  return

FFTCGDB::close = ->
  new Promise (resolve, reject) ->
    @db.close (err) ->
      if err
        resolve "[FFTCGDB] Error closing: '#{err.message}'"
      else
        reject "[FFTCGDB] Closed '#{@filename}'"

FFTCGDB::register = (login, password) ->
  that = @

  new Promise (resolve, reject) ->
    # validate username

    # hash password
    bcrypt.hash password, saltRounds, (err, hash) ->
      reject 'hash' if err
      # try creating row in users table
      that.db.run "INSERT INTO users (login, pwdhash) VALUES ('#{login}', '#{hash}');", (err) ->
        if err
          if err.code == 'SQLITE_CONSTRAINT'
            reject 'existence'
          else
            reject 'db'

        else
          # registration successful
          resolve @lastID

FFTCGDB::login = (login, password) ->
  that = @

  new Promise (resolve, reject) ->
    # validate username

    # get users table row
    that.db.all "SELECT rowid, pwdhash FROM users WHERE login = '#{login}';", (err, rows) ->
      if err
        reject 'db'

      else if rows.length == 0
        # hashing the password for timing attack reasons
        bcrypt.hash password, saltRounds, (err, hash) ->
          reject 'existence'

      else
        row = rows[0]
        bcrypt.compare password, row.pwdhash, (err, res) ->
          reject 'hash' if err
          if res == true
            resolve row.rowid
          else
            reject 'login'

module.exports = FFTCGDB
