const hapi = require("./hapi");
const _ = require("lodash");
const Logger = require("./Logger");

const apiGet = entity => async (api, {id, select}) => {
  select && (select = select.join(" "));
  if(id.length == 1) return await api[entity].get({id: id[0], query: {select}});
  return (
    await Promise.all(_.uniq(id).map(id => api[entity].get({id, query: {select}})))
  ).filter(res => res && res.data).map(({data}) => data);
}

const apiList = entity => (api, {filter, skip, limit, select, sort, ...other}) => {
  other = _.omit(other, ["$0", "_", "u", "p", "h", "username", "password", "host", "console", "help", "version"]);
  return api[entity].list({
    query: {filter: {...filter && JSON.parse(filter), ...other}, sort, skip, limit, select: select && select.join(" ")}
  });
};

const apiRemove = entity => async (api, {id, ...argv}) => {
  if(id.length == 1) {
    id = id[0];
    if(!id.trim().startsWith("{"))
      return await api[entity].remove({id});
    const filter = JSON.parse(id);
    const log = Logger(argv);
    const res = {data: {n: 0}};
    for(;;) {
      const {data} = await api[entity].list({query: {filter, select: "_id"}});
      if(!data.length) break;
      for(const {_id} of data) {
        await api[entity].remove({_id});
        log.error(`removed ${_id}`);
        res.data.n++;
      }
    }
    return res;
  }

  return (
    await Promise.all(_.uniq(id).map(id => api[entity].remove({id})))
  ).reduce((acc, val) => (acc.data.n += _.get(val, "data.n", 0), acc), {data: {n: 0}});
}

const apiUpdate = entity => async (api, {id, data}) => {
  const {data: [obj]} = await api[entity].list({query: {filter: {_id: id}, select: "__v"}});
  if(!obj) throw "Not Found";
  return await api[entity].update({data: JSON.parse(data), id, __v: obj.__v});
};
const apiAdd = entity => (api, {data}) => api[entity].add({data: JSON.parse(data)});

module.exports = (entity, {
  list = {}, get: getOne = {}, remove = {}, update = {}, add = {}
} = {}) => yargs => {
  list && yargs.command({
    command: ["list", "ls"],
    desc: "List all",
    builder: yargs => yargs
      .option("filter", {desc: 'Filter JSON --filter=\'{"role":"admin"}\''})
      .option("limit",  {number: true, default: 50, desc:"Maximum return items"})
      .option("skip",   {number: true, default: 0,  desc:"Count items too skip"})
      .option("sort",   {desc: "Order by"})
      .option("select", {array: true, desc: "list required fields"}),
    handler: hapi(apiList(entity, list))
  });
  getOne && yargs.command({
    command: "get <id...>",
    desc: "Get one by id",
    builder: yargs => yargs.array("id").option("select", {array: true, desc: "list required fields"}),
    handler: hapi(apiGet(entity, getOne))
  });
  remove && yargs.command({
    command: "remove <id...>",
    aliases: ["rm"],
    desc: "Remove one by id",
    builder: yargs => yargs.array("id"),
    handler: hapi(apiRemove(entity, remove))
  });
  update && yargs.command({
    command: "update <id> <data>",
    aliases: ["up"],
    desc: "Update one by id",
    handler: hapi(apiUpdate(entity, update)),
    ...update.command
  });
  add && yargs.command({
    command: "add <data>",
    desc: "Add new",
    handler: hapi(apiAdd(entity, update)),
    ...add.command
  });
  return yargs;
}
