'use strict';

/**
 * create table users
 *
 * @param {any} knex database connection
 * @returns {Promise} result
 */
function create_users (knex) {
  return knex.schema.createTable ('users', (table) => {
    table.increments ('id');
    table.string ('name');
    table.string ('email');
    table.string ('password');
    table.string ('salt');
    table.boolean ('deleted');

    table.unique ('name', 'email');
  });
}

/**
 * create table applications
 *
 * @param {any} knex database connection
 * @returns {Promise} result
 */
function create_applications (knex) {
  return knex.schema.createTable ('applications', (table) => {
    table.increments ('id');
    table.string ('name');
  });
}

/**
 * create table permissions
 *
 * @param {any} knex database connection
 * @returns {Promise} result
 */
function create_permissions (knex) {
  return knex.schema.createTable ('permissions', (table) => {
    table.increments ('id');
    table.integer ('user_id');
    table.boolean ('create_app');
    table.boolean ('manage_users');
    table.boolean ('manage_permissions');
    table.boolean ('manage_apps');
    table.boolean ('manage_keys');
    table.boolean ('issue_key');

    table.foreign ('user_id')
      .references ('id')
      .inTable ('users');
  });
}

/**
 * create table user_access
 *
 * @param {any} knex database connection
 * @returns {Promise} result
 */
function create_user_access (knex) {
  return knex.schema.createTable ('user_access', (table) => {
    table.increments ('id');
    table.integer ('user_id');
    table.integer ('app_id');
    table.string ('crud');

    table.foreign ('user_id')
      .references ('id')
      .inTable ('users');
    table.foreign ('app_id')
      .references ('id')
      .inTable ('applications');
  });
}

/**
 * create table auth_keys
 *
 * @param {any} knex database connection
 * @returns {Promise} result
 */
function create_auth_keys (knex) {
  return knex.schema.createTable ('auth_keys', (table) => {
    table.increments ('id');
    table.string ('key');
    table.integer ('app_id');
    table.boolean ('read_data');
    table.string ('hash');
    table.string ('name');

    table.unique ('key', 'hash');

    table.foreign ('app_id')
      .references ('id')
      .inTable ('applications');
  });
}

/**
 * create table categories
 *
 * @param {any} knex database connection
 * @returns {Promise} result
 */
function create_categories (knex) {
  return knex.schema.createTable ('categories', (table) => {
    table.increments ('id');
    table.string ('name');
    table.integer ('app_id');

    table.unique ('name');

    table.foreign ('app_id')
      .references ('id')
      .inTable ('applications');
  });
}

/**
 * create table log
 *
 * @param {any} knex database connection
 * @returns {Promise} result
 */
function create_log (knex) {
  return knex.schema.createTable ('log', (table) => {
    table.increments ('id');
    table.integer ('key_id');
    table.integer ('app_id');
    table.integer ('timestamp');
    table.integer ('category_id');

    table.foreign ('key_id')
      .references ('id')
      .inTable ('auth_keys');
    table.foreign ('app_id')
      .references ('id')
      .inTable ('applications');
    table.foreign ('category_id')
      .references ('id')
      .inTable ('categories');
  });
}

/**
 * create table data
 *
 * @param {any} knex database connection
 * @returns {Promise} result
 */
function create_data (knex) {
  return knex.schema.createTable ('data', (table) => {
    table.increments ('id');
    table.integer ('log_id');
    table.string ('key');
    table.string ('value');

    table.foreign ('log_id')
      .references ('id')
      .inTable ('log');
  });
}

/**
 * run migration
 *
 * @param {any} knex db connection
 */
async function up (knex) {
  await create_users (knex);
  await create_applications (knex);
  await create_permissions (knex);
  await create_user_access (knex);
  await create_auth_keys (knex);
  await create_categories (knex);
  await create_log (knex);
  await create_data (knex);
}

/**
 * revert migration
 */
function down () {
  // noop
}

module.exports = { up, down };