import { knex, validation } from '../../lib/ormish.js';
import logging from "../../lib/logging.js";
import { developer_admin, API } from '../../lib/api.js';

const log = logging.create("api/admin/table.js");

export const get = async (req, res) => {
  const api = new API(req, res);
  const { name, search, row_id, currentPage } = req.query;

  try {
    const page = parseInt(currentPage || "0", 10);

    if(!api.admin_authenticated) {
      return api.error(401, "Admin rights required.");
    } else if(name && search) {
      // get the list of columns to search
      const col_info = await knex(name).columnInfo();
      const query = knex(name);
      let columns = Object.getOwnPropertyNames(col_info);

      for(let col of columns) {
        // SECURITY: string interpolation but not sure how to do this without it
        query.orWhere(col, "like", `%${search}%`);
      }

      // loop through and construct a mega where clause
      let result = await query.paginate({perPage: 20, currentPage: page});

      return api.reply(200, result);
    } else if(name && !row_id) {

      // TODO: restrict the tables that can be queried?
      let result = await knex(name).paginate({perPage: 20, currentPage: page});

      return api.reply(200, result);
    } else if(name && row_id) {
      let result = await knex(name).where({id: row_id}).first();
      return api.reply(200, result);
    } else {
      return api.error(500, "name query parameter required, or name and row_id.");
    }
  } catch(error) {
    log.error(error);
    return api.error(500, "Internal server error.");
  }
}

get.authenticated = !developer_admin;

export const del = async (req, res) => {
  const api = new API(req, res);
  const { name, row_id } = req.query;

  try {
    if(!api.admin_authenticated) {
      return api.error(401, "Admin rights required.");
    } else if(name && row_id) {
      let res = await knex(name).where({id: row_id}).delete();
      return api.reply(200, {message: "OK", result: res});
    } else {
      return api.error(500, "name and row_id required for delete");
    }
  } catch(error) {
    log.error(error);
    return api.error(500, "Internal server error.");
  }
}

del.authenticated = !developer_admin;

export const post = async (req, res) => {
  const api = new API(req, res);
  const { name, row_id } = req.query;

  try {
    if(!api.admin_authenticated) {
      return api.error(401, "Admin rights required.");
    } else if(name && row_id) {
      // normally the validation rules come from the
      // model class once and placed at the top of the
      // module, but here we get it dynamically based
      // on the name.
      const rules = validation(name, {}, true);
      const data = api.validate(rules);

      // remove the id since they can't set it
      delete data["id"];

      if(!data._valid) {
        return api.validation_error(res, data);
      } else {
        // remove id so it's not updated too
        api.clean_form(data, rules, ["id"]);
        let res = await knex(name).
          where({id: row_id}).update(data);

        return api.reply(200, {message: "OK", result: res});
      }
    } else {
      return api.error(500, "name and row_id required for delete");
    }
  } catch(error) {
    log.error(error);
    return api.error(500, error.message || "Internal server error.");
  }
}

post.authenticated = !developer_admin;

export const put = async (req, res) => {
  const api = new API(req, res);
  const { name } = req.query;

  try {
    if(!api.admin_authenticated) {
      return api.error(401, "Admin rights required.");
    } else if(name) {
      const rules = validation(name, {}, true);
      // don't validate id or accept it
      const data = api.validate(rules);

      // remove the id since they can't set it
      delete data["id"];

      if(!data._valid) {
        return api.validation_error(res, data);
      } else {
        api.clean_form(data, rules, ["id"]);
        let res = await knex(name).insert(data);

        return api.reply(200, {message: "OK", id: res[0]});
      }
    } else {
      return api.error(500, "name required for delete");
    }
  } catch(error) {
    log.error(error);
    return api.error(500, "Internal server error.");
  }
}

put.authenticated = !developer_admin;
