--local xxhash = require( "xxhash" )
--local uuid = require( 'resty.jit-uuid' )
local uuid = require( 'lua_uuid' )
local DB = require( "./piazza-lmdb" )
local db = DB.init()

local user = require'./models/user'
local item = require'./models/item'
local image = require'./models/image'
local thumbnail = require'./models/thumbnail'
local cart = require'./models/cart'
local lineitem = require'./models/lineitem'
local order = require'./models/order'
local customprice = require'./models/customprice'
local application = require'./models/application'

local util = require( './piazza-util' )

local models = {user, item, image, thumbnail, cart, lineitem, order, customprice, application}
for _, model in ipairs(models) do
  model.setdb(db)
end

-- password hash:
local hash = util.hash

local sessions = {}  -- keys are session_hashes, values are whatever the server wants to store

local validate = util.validate

local api = {};
api.post = function()
  return {message="I did a post."}
end

api.attemptlogin = function(req)
  local validation_errors = validate(req, {
    username = {'string', required=true},
    password = {'string', required=true}
    })
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local user_record = db:findOne(function(record)
      return record.type == 'user' and record.username == req.username
      end)
    if user_record == nil then
      return {success = false, error="no such user"}
    elseif user_record.password_hash ~= hash(req.password) then
      return {success = false, error="wrong password"}
    -- TODO: add 'elseif' to make sure user isn't already logged-in, so two sessions aren't made for the same user who clicked 'login' button twice; although this will make it impossible to sign-in from two different computers
    else
      local session_hash = uuid()
      sessions[session_hash] = {user_id = user_record.id}
      if user_record.current_cart_id == nil then
        cart.newForUser(user_record)
      end
      return {
        success = true, 
        -- user = db:preparecopy(user_record, {'password_hash'}), 
        -- cart = db:preparecopy(user_record.current_cart),
        user = user_record:copyandtransform({
          id = 'copy',
          username = 'copy',
          firstname = 'copy',
          tier = 'copy',
          is_admin = 'copy'
          }),
        cart = db:getrecord(user_record.current_cart_id):copyandtransform({
          id = 'copy',
          lineitem_ids = {'list', {
            id = 'copy',
            quantity = 'copy',
            price = 'copy',
            item_id = {
              id = 'copy',
              name = 'copy',
              brand = 'copy',
              model = 'copy',
              color = 'copy'
              }
            }}
          }),
        session_hash = session_hash
      }
    end
  end
end

api.logout = function(req)
  local session_hash = req.session_hash
  if session_hash ~= nil and sessions[session_hash] ~= nil then
    sessions[session_hash] = nil
    return {success=true}
  else
    return {error="no such session_hash"} -- TODO: this could happen if user logged-in, then fastcgi was restarted (thus clearing the sessions table), and then logged-out
  end
end

api.getone = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true},
    ['type'] = {'string', required=true},
    id = {'db_ref', to=req['type'], required=true, load_as='record'},
    structure = {'table', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local record_copy = loaded_records.record:copyandtransform(req.structure)
    return {success = true, record = record_copy}
  end
end

--[[ -- too big of a security concern. it could return the whole DB to a clever attacker
api.getall = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true},
    filter = {'table', required=true},  -- TODO: ensure 'filter' is a non-empty table, for security reasons, because then the whole DB will be returned
    structure = {'table', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local records = db:findByStructure(req.filter)
    local record_copies = db:copyandtransformall(records, req.structure)
    return {success=true, records = record_copies}
  end
end
]]

api.setproperty = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    record_type = {'string', required=true},
    record_id = {'db_ref', to=req.record_type, required=true, load_as='record'},
    key = {'string', required=true}
    -- value = {'string', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local record = loaded_records.record
    record[req.key] = req.value
    record:save()
    return {success=true}
  end
end

api.insertrecord = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true},
    record = {'table', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local id = db:insertrecord(req.record)
    return {success=true, id = id}
  end
end


-- admin function: add item
api.additem = function(req)
  local validation_errors = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    item = {'table', required=true}
    }, nil, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    item.new(req.item)
    -- if saving succeeds, return success message
    return {success=true}
  end
end

-- admin function: delete item
api.deleteitem = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    item_id = {'db_ref', to='item', required=true, load_as='item_record'}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    -- delete item
    --loaded_records.item_record:delete()
    loaded_records.item_record.deleted = true
    loaded_records.item_record:save()
    -- if deletion succeeds, return success message
    return {success=true}
  end
end

-- admin function: update item
-- session_hash, item_id, properties_to_update
api.updateitem = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    item_id = {'db_ref', to='item', required=true, load_as='item_record'},
    properties_to_update = {'table', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    util.merge(loaded_records.item_record, req.properties_to_update)
    loaded_records.item_record:save()
    --db:update(loaded_records.item_record, req.properties_to_update)
    -- if update succeeds, reply with success
    return {success=true}
  end
end

api.fulliteminfo = function(req)
  local validation_errors, loaded_records = validate(req, {
    item_id = {'db_ref', to='item', required=true, load_as='item_record'}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local item_record_copy = loaded_records.item_record:copyandtransform({
      id = 'copy',
      ['type'] = 'copy',
      description_short = 'copy',
      size = 'copy',
      material = 'copy',
      color_description = 'copy'
      })
    -- if update succeeds, reply with success
    return {success=true, item=item_record_copy}
  end
end

--[[
api.newimage = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    image_base64 = {'base64', required=true, load_as = 'image_base64'},
    original_filename = {'string', required=true}  -- so we can tell for which frame it is in retrospect
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    image.new_from_base64(loaded_records.image_base64, req.original_filename, db) 
    return {success=true}
  end
end
]]

-- admin function: create new empty frame record
-- session_hash
api.createnewframe = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local new_frame_record = item.new({
      subtype='frame',
      brand='',
      model='',
      color = '',
      color_description = '',
      name = '',
      description_short = '',
      size = '',
      material = '',
      price_silver = 0,
      price_gold = 0,
      inventory = 0
      })
    local new_frame_record_copy = new_frame_record:copyandtransform({
                    id = 'copy',
                    ['type'] = 'copy',
                    subtype = 'copy',
                    brand = 'copy',
                    model = 'copy',
                    color = 'copy',
                    color_description = 'copy',
                    name = 'copy',
                    description_short = 'copy',
                    size = 'copy',
                    material = 'copy',
                    price_silver = 'copy',
                    price_gold = 'copy',
                    inventory = 'copy'
                    })
    -- if update succeeds, reply with success
    return {success=true, new_frame=new_frame_record_copy}
  end
end

-- admin function: add image to item
-- session_hash, item_id, image_base64, original_filename
api.addimagetoitem = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    item_id = {'db_ref', to='item', required=true, load_as='item_record'},
    image_base64 = {'base64', required=true, load_as='image_base64'},
    original_filename = {'string', required=true}  -- so we can tell for which frame it is in retrospect
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local image_record = image.new_from_base64(loaded_records.image_base64, req.original_filename)
    local item_record = loaded_records.item_record
    -- image_record.item = item_record   -- not all images have a `.item` property, so we should rather link the image to the item by `item.images`
    if item_record.image_ids == nil then item_record.image_ids = {} end
    table.insert(item_record.image_ids, image_record.id)
    item_record:save()
    local image_record_copy = image_record:copyandtransform({
                    id = 'copy',
                    ['type'] = 'copy',
                    original_filename = 'copy',
                    thumbnail_960_id = 'copy',
                    thumbnail_180_id = 'copy',
                    thumbnail_original_id = 'copy'
                    })
    -- if update succeeds, reply with success
    return {success=true, image=image_record_copy}
  end
end

api.deleteitemimage = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    item_id = {'db_ref', to='item', required=true, load_as='item_record'},
    image_id = {'db_ref', to='image', required=true, load_as='image_record'}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local image_record = loaded_records.image_record
    local item_record = loaded_records.item_record
    -- image_record.item = item_record   -- not all images have a `.item` property, so we should rather link the image to the item by `item.images`
    if item_record.image_ids == nil then item_record.image_ids = {} end
    local image_index = 0
    repeat
      image_index = image_index + 1
    until item_record.image_ids[image_index] == image_record.id or item_record.image_ids[image_index] == nil
    
    table.remove(item_record.image_ids, image_index)
    item_record:save()
    -- also delete the image_record, and the files it points to
    image_record:delete()
    
    db:delete(image_record.thumbnail_original_id)
    db:delete(image_record.thumbnail_960_id)
    db:delete(image_record.thumbnail_180_id)
    
    -- if update succeeds, reply with success
    return {success=true}
  end
end

api.itemsbystring = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true},
    search_string = {'string', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local item_records = db:findAll(function(record)
      return record.type == 'item' and string.find(record.model, req.search_string) ~= nil
      end)
    item_records = db:copyandtransformall(item_records, {
          id = 'copy',
          ['type'] = 'copy',
          brand = 'copy',
          model = 'copy',
          color = 'copy'
          })
    return {success=true, results = item_records}
  end
end

api.framesbystring = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true},
    search_string = {'string', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local item_records = db:findAll(function(record)
      return record.subtype == 'frame' and string.find(record.model, req.search_string) ~= nil
      end)
    item_records = db:copyandtransformall(item_records, {
          id = 'copy',
          ['type'] = 'copy',
          subtype = 'copy',
          name = 'copy',
          brand = 'copy',
          model = 'copy',
          color = 'copy',
          color_description = 'copy',
          description_short = 'copy',
          size = 'copy',
          material = 'copy',
          price_silver = 'copy',
          price_gold = 'copy',
          inventory = 'copy'
          })
    return {success=true, results = item_records}
  end
end

api.itemimages = function(req)
  local validation_errors, loaded_records = validate(req, {
    --session_hash = {'session', required=true},
    item_id = {'db_ref', to='item', required=true, load_as='item_record'}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local item_record = loaded_records.item_record
    if item_record.image_ids == nil then
      item_record.image_ids = {}
      item_record:save()
    end
    local image_records = db:copyandtransformall(item_record.image_ids, {
            id = 'copy',
            ['type'] = 'copy',
            original_filename = 'copy',
            thumbnail_960_id = 'copy',
            thumbnail_180_id = 'copy',
            thumbnail_original_id = 'copy'
            })
    return {success=true, images = image_records}
  end
end

-- admin function: change user's tier
-- session_hash, user_id, tier
api.changeusertier = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    user_id = {'db_ref', to='user', required=true, load_as='user_record'},
    tier = {'string', required=true, is_any_of={'gold','silver'}}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    --db:update(loaded_records.user_record, {tier=req.tier})
    loaded_records.user_record.tier = req.tier
    loaded_records.user_record:save()
    -- if update succeeds, reply with success
    return {success=true}
  end
end

-- admin function: give custom price to user for certain item
-- session_hash, user_id, item_id, price
api.setuseritemprice = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    user_id = {'db_ref', to='user', required=true, load_as='user_record'},
    item_id = {'db_ref', to='item', required=true, load_as='item_record'},
    price = {'number', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    -- find previously-existing special price between this user and this item
    local custom_price_record = db:findOne(function(record) return record.type == 'custom_price' and record.user_id == loaded_records.user_record.id and record.item_id == loaded_records.item_record_id end)
    -- if no existing special price is found, insert one into DB
    if custom_price_record == nil then
      customprice.new({user_id=loaded_records.user_record.id, item_id=loaded_records.item_record.id, price=req.price})
      -- if insert succeeds, reply with success
      return {success=true}
      -- if insert fails, reply with error
    -- if existing special price is found, update it
    else
      --db:update(custom_price_record, {price = req.price})
      custom_price_record.price = req.price
      custom_price_record:save()
      -- if update succeeds, reply with success
      return {success=true}
      -- if update fails, reply with error
    end
  end
end

-- function: update item quantity in current cart; if zero, remove; if was zero, add to cart
api.updateitemquantityincart = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true},
    item_id = {'db_ref', to='item', required=true, load_as='item_record'},
    quantity = {'number', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    -- find cart based on session_hash
    local current_user_record = db:getrecord( loaded_records.session.user_id )
    local cart_record = db:getrecord(current_user_record.current_cart_id)
    -- if cart not found, create one
    if cart_record == nil then
      cart_record = cart.newForUser(current_user_record)
    end
    -- find lineitem for this item in cart
    local lineitem_record_id = util.findOne(cart_record.lineitem_ids, function(lineitem_id)
        local lineitem = db:getrecord(lineitem_id)
        return lineitem.item_id == loaded_records.item_record.id
        end)
    local lineitem_record
    -- if lineitem not found, create one
    if lineitem_record_id == nil then
      if req.quantity > 0 then
        lineitem_record = lineitem.new({cart=cart_record, item=loaded_records.item_record, quantity=req.quantity})
      end
    else
      lineitem_record = db:getrecord(lineitem_record_id)
      if req.quantity > 0 then
        -- update quantity in lineitem
        --db:update(lineitem_record, {quantity = req.quantity})
        lineitem_record.quantity = req.quantity
        lineitem_record:save()
      -- if the item is being removed from the cart
      elseif req.quantity == 0 then
        -- remove item from cart
        util.removefromtable(cart_record.lineitem_ids, lineitem_record.id)
        --db:remove(lineitem_record)
        lineitem_record:delete()
        cart_record:save()
      end
    end
    local lineitem_records_copy = db:copyandtransformall(cart_record.lineitem_ids, {
        id = 'copy',
        ['type'] = 'copy',
        item_id = {
          id = 'copy',
          ['type'] = 'copy',
          name = 'copy',
          brand = 'copy',
          model = 'copy',
          color = 'copy',
          price_silver = 'copy',
          price_gold = 'copy',
          inventory = 'copy',
          price = 'copy',
          },
        quantity = 'copy',
        price = 'copy'
      })
    return {success=true, lineitems = lineitem_records_copy}
  end
end

-- function: place order (i.e. current cart)
api.placeorder = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    -- find cart based on session_hash
    local current_user_record = db:getrecord( loaded_records.session.user_id )
    local cart_record = db:getrecord( current_user_record.current_cart_id )
    -- if cart not found, reply with error
    if cart_record == nil then
      return {error="No cart for current user."}
    elseif #cart_record.lineitem_ids == 0 then
      return {error="Cart is empty."}
    else
      -- if cart found, create order out of it
      local order_record = order.new({cart=cart_record})
      -- if order creation successful, create new empty cart for user and reply with success
      for _, lineitem_id in ipairs(cart_record.lineitem_ids) do
        local lineitem_record = db:getrecord(lineitem_id)
        local item_record = db:getrecord(lineitem_record.item_id)
        item_record.inventory = item_record.inventory - lineitem_record.quantity
        item_record:save()
      end
      local new_cart_record = cart.newForUser(current_user_record)
      return {success=true, order_id = order_record.id, new_cart_record = new_cart_record}
    end
  end
end

-- admin function: list open orders
api.listopenorders = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    -- find open orders
    local open_order_records = db:findAll(function(record)
      return record.type == 'order' and record.status == 'open'
      end)
    -- local open_orders = db:preparecopies(open_order_records)
    local open_orders = db:copyandtransformall(open_order_records, {
        id = 'copy',
        ['type'] = 'copy',
        cart_id = 'copy',
        user_id = {
          id = 'copy',
          ['type'] = 'copy',
          firstname = 'copy',
          lastname = 'copy',
          store = 'copy'
          },
        date_ordered = 'copy',
        status = 'copy',
        progress = 'copy'
        })
    return {success=true, orders=open_orders}
  end
end

-- admin function: list open orders
api.loadorder = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    order_id = {'db_ref', to='order', load_as='order_record'}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local order_record_copy = loaded_records.order_record:copyandtransform({
        id = 'copy',
        ['type'] = 'copy',
        progress = 'copy',
        cart_id = {
          id = 'copy',
          ['type'] = 'copy',
          lineitem_ids = {
            'list',
            {
              id = 'copy',
              ['type'] = 'copy',
              price = 'copy',
              quantity = 'copy',
              item_id = {
                id = 'copy',
                ['type'] = 'copy',
                name = 'copy'
                }
              }
            }
          }
        })
    return {success=true, order=order_record_copy}
  end
end

-- admin function: mark order as packed, shipped, and delivered
api.updateorderstatus = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    order_id = {'db_ref', to='order', required=true, load_as='order_record'},
    status = {'string', required=true, is_any_of={'open','packed','shipped','paid'}}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    -- if order found, update status
    --db:update(loaded_records.order_record, {status = req.status})
    loaded_records.order_record.status = req.status
    loaded_records.order_record:save()
    -- if update succeeds, reply with success
    return {success=true}
  end
end

-- function: find items according to privileges and characteristics
api.itemsbyfilter = function(req)
  local filter = req.filter
  local item_records = db:findAll(function(record)
    if record.type ~= 'item' then return false end
    --if record.inventory == nil then record.inventory = 0; record:save() end
    if record.inventory < 1 then return false end
    -- if user is not signed-in, he cannot see all items:
    if req.session_hash == nil then
      for k,v in pairs(filter) do
        if record[k] ~= v then return false end
        if item.restricted == true then return false end
      end
    -- if user is signed-in, he may see all items:
    else
      for k,v in pairs(filter) do
        if record[k] ~= v then return false end
      end
    end
    return true
  end)
  local item_records_copy = db:copyandtransformall(item_records, {
    id = 'copy',
    name = 'copy',
    brand = 'copy',
    model = 'copy',
    color = 'copy',
    color_description = 'copy',
    size = 'copy',
    material = 'copy',
    description_short = 'copy', 
    price_gold = 'copy',
    price_silver = 'copy',
    inventory = 'copy',
    image_ids = {
      'list',
      {
        id = 'copy',
        ['type'] = 'copy',
        thumbnail_180_id = 'copy',
        thumbnail_960_id = 'copy',
        thumbnail_original_id = 'copy'
        }
      }
    })
  -- TODO: only send the price for each item according to the user's tier, or his own special pricing. don't send price_silver and price_gold
  return {success=true, items = item_records_copy}
end

-- function: submit new user application, to be accepted or declined by admin
api.submitnewuserapplication = function(req)
  local validation_errors, loaded_records = validate(req, {
    username = {'string', required=true},
    salutation = {'string', required=true, is_any_of={'mr','ms','mrs','dr'}},
    firstname = {'string', required=true},
    lastname = {'string', required=true},
    position = {'string', required=true},
    store = {'string', required=true},
    address = {'string', required=true},
    practice_type = {'string', required=true},
    phone_office = {'string', required=true},
    phone_cell = {'string', required=true},
    email = {'string', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    application.new({
      ['type'] = 'application',
      username = req.username,
      salutation = req.salutation,
      firstname = req.firstname,
      lastname = req.lastname,
      position = req.position,
      store = req.store,
      address = req.address,
      practice_type = req.practice_type,
      phone_office = req.phone_office,
      phone_cell = req.phone_cell,
      email = req.email
      })
    -- if update succeeds, reply with success
    return {success=true}
  end
end

api.acceptnewuserapplication = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    application_id = {'db_ref', to='application', required=true, load_as='application_record'},
    password = {'string', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    local application_record = loaded_records.application_record
    user.new({
      password = req.password,
      username = application_record.username,
      salutation = application_record.salutation,
      firstname = application_record.firstname,
      lastname = application_record.lastname,
      position = application_record.position,
      store = application_record.store,
      address = application_record.address,
      practice_type = application_record.practice_type,
      phone_office = application_record.phone_office,
      phone_cell = application_record.phone_cell,
      email = application_record.email,
      tier='silver'
      })
    --db:update(application_record, {status = 'accepted', accepted_at = os.time()})
    application_record.status = 'accepted'
    application_record.accepted_at = os.time()
    application_record:save()
    -- if update succeeds, reply with success
    return {success=true}
  end
end

-- admin function: list open application records
api.listnewuserapplications = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    -- find open applications
    local open_application_records = db:findAll(function(record) return record.type == 'application' and record.status == 'open' end)
    local open_applications = db:copyandtransformall(open_application_records, {
      id='copy',
      ['type'] = 'copy',
      username = 'copy',
      salutation = 'copy',
      firstname = 'copy',
      lastname = 'copy',
      position = 'copy',
      store = 'copy',
      address = 'copy',
      practice_type = 'copy',
      phone_office = 'copy',
      phone_cell = 'copy',
      email = 'copy',
      submitted_at = 'copy'
      })
    return {success=true, open_applications=open_applications}
  end
end

api.declinenewuserapplication = function(req)
  local validation_errors, loaded_records = validate(req, {
    session_hash = {'session', required=true, is_admin=true},
    application_id = {'db_ref', to='application', required=true, load_as='application_record'},
    password = {'string', required=true}
    }, db, sessions)
  if #validation_errors > 0 then
    return {errors=validation_errors}
  else
    --db:update(loaded_records.application_record, {status = 'declined', declined_at = os.time()})
    local application_record = loaded_records.application_record
    application_record.status = 'declined'
    application_record.declined_at = os.time()
    application_record:save()
    -- if update succeeds, reply with success
    return {success=true}
  end
end

api.getthumbnail = function(thumbnail_id)
  return db:getrecord(thumbnail_id).src
end

return api
