
/* <%- lintDisableUnused %>, indent */
// Define GraphQL resolvers using only Feathers services. (Can be re-generated.)
<%- tplTsOnly([
  `import { App } from '../../app.interface'${sc}`,
  `import { Paginated } from '@feathersjs/feathers'${sc}`,
  `import { FGraphQLResolverMap } from 'feathers-hooks-common'${sc}`,
  '',
]) -%>
<%- insertFragment('imports') %>
<%- insertFragment('init') %>

<%- tplTsOnly([
  'export interface ServiceResolverOptions {',
  '  convertArgsToFeathers: any;',
  '  extractAllItems: any;',
  '  extractFirstItem: any;',
  '}',
  '',
  '',
]) -%>
let moduleExports = function serviceResolvers<%- tplJsOrTs('(app, options)', '(app: App, options: ServiceResolverOptions)') %> {
  const {convertArgsToFeathers, extractAllItems, extractFirstItem} = options<%- sc %>
  <%- insertFragment('extra_auth_props', [
    `  const convertArgs = convertArgsToFeathers([])${sc}`,
  ]) %>

<% let __temp = Object.keys(mapping.feathers).map(serviceName =>
  `  let ${serviceName} = app.service('${mapping.feathers[serviceName].path}')${sc}`
); -%>
  <%- insertFragment('services', __temp) %>

  let returns<%- tplTsOnly(': FGraphQLResolverMap') -%> = {
<%# -%>
<%# --- forEach-1 starts below. Loop thru the schemas of GraphQL enabled services. -%>
<% Object.keys(mapping.graphqlService).forEach(graphqlName => {
  __serviceName = mapping.graphqlService[graphqlName].service;
  __add = feathersSpecs[__serviceName]._extensions.graphql.add;
-%>

    <%- graphqlName %>: {
<%# -%>
<%# --- forEach-2 starts below. Loop thru the fields to be added. -%>
<% Object.keys(__add).forEach(fieldName => {
  __addField = __add[fieldName];

  if (__addField.isArray) {
    __$sort = `$sort: ${!__addField.sort ? 'undefined' : '\n' + stringifyPlus(__addField.sort, { indentBy: 14 })}`;
  } else {
    __$sort = '';
  }
-%>

      // <%- fieldName %><%- __addField.args %>: <%- __addField.type %>
      <%- fieldName %>:
<%# -%>
<%# --- if/else-1 starts below. Whether field is a join or a calculated field. -%>
<% if (__addField.serviceName) {
  // Field in other table is not an array
  if (!__addField.relation.otherTableIsArray) {
    __temp = [
      '        (parent, args, content, ast) => {',
      '          const feathersParams = convertArgs(args, content, ast, {',
      `            query: { ${__addField.relation.otherTable}: `
        + `${__addField.relation.ourTableIsArray ? '{ $in: ' : ''}parent.${__addField.relation.ourTable}${__addField.relation.ourTableIsArray ? ' }' : ''}`
        + `${__$sort ? `, ${__$sort}` : ''} }, paginate: false`,
      `          })${sc}`,
      !__addField.isArray // If an array is being returned
         ? `          return ${__addField.serviceName}.find(feathersParams).then(extractFirstItem)${sc}`
         : `          return ${__addField.serviceName}.find(feathersParams).then(extractAllItems)${sc}`,
      '        },'
    ];
  } else {
  // Field in other table is an array
    __temp = [
      '        (parent, args, content, ast) => {',
      '          const feathersParams = convertArgs(args, content, ast, {',
      `            query: { ${__$sort} }, paginate: false`,
      `          })${sc}`
    ];

    if (!__addField.isArray) {
      __temp = __temp.concat([
        `          return ${__addField.serviceName}.find(feathersParams).then(extractFirstItem)${sc}`,
        '        },'
      ]);
    } else {
      __temp = __temp.concat([
        '',
        `          if (!(content.cache.${graphqlName} && content.cache.${graphqlName}.${fieldName})) {`,
        `            content.cache.${graphqlName} = content.cache.${graphqlName} || {}${sc}`,
        `            content.cache.${graphqlName}.${fieldName} = ${__addField.serviceName}.find(feathersParams).then(extractAllItems)${sc}`,
        `          }`,
        '',
        `          return Promise.resolve(content.cache.${graphqlName}.${fieldName})`,
        `            .then(res => res.filter(rec => rec.${__addField.relation.otherTable}.map(key => key.toString()).indexOf(parent._id.toString()) !== -1))${sc}`,
        '        },'
      ]);
    }
  }
-%>
        <%- insertFragment(`resolver-${graphqlName}-${fieldName}`, __temp) %>
<% } else { -%>
        <%- insertFragment(`resolver-${graphqlName}-${fieldName}-non`,
          `        (parent, args, content, ast) => { throw Error('GraphQL fieldName ${graphqlName}.${fieldName} is not calculated.')${sc} },`
        ) %>
<% } -%>
<%# --- if/else-1 ends above. -%>
<% }); -%>
<%# --- forEach-2 ends above. -%>
    },
<% }); -%>
<%# --- forEach-1 ends above. -%>

    <%- insertFragment('resolver_field_more') %>

    Query: {
<%# -%>
<%# --- forEach-3 starts below. Loop thru the schemas of GraphQL enabled services. -%>
<% Object.keys(mapping.graphqlService).forEach(graphqlName => {
  __serviceName = mapping.graphqlService[graphqlName].service;
  __graphql = feathersSpecs[__serviceName]._extensions.graphql;
  __temp = [
    `      // get${graphqlName}(query: JSON, params: JSON, key: JSON): ${graphqlName}`,
    `      get${graphqlName}(parent, args, content, ast) {`,
    `        const feathersParams = convertArgs(args, content, ast)${sc}`,
    `        return ${__serviceName}.get(args.key, feathersParams).then(extractFirstItem)${sc}`,
    '      },',
    '',
    `      // find${graphqlName}(query: JSON, params: JSON): [${graphqlName}!]`,
    `      find${graphqlName}(parent, args, content, ast) {`,
    `        const feathersParams = convertArgs(args, content, ast${__graphql.serviceSortParams})${sc}`,
    `        return ${__serviceName}.find(feathersParams).then(paginate(content)).then(extractAllItems)${sc}`,
    '      },',
  ];
-%>

      <%- insertFragment(`query-${graphqlName}`, __temp) %>
<% }); -%>
<%# --- forEach-3 ends above. -%>
      <%- insertFragment('resolver_query_more') %>
    },
  }<%- sc %>

  <%- insertFragment('func_return') %>
  return returns<%- sc %>
}<%- sc %>

<%- insertFragment('more') %>

<%- insertFragment('exports') %>
<%- `${tplExport('moduleExports')}${sc}` %>

function paginate(content<%- tplTsOnly(': any') -%>) {
  return <%- tplJsOrTs('result', '(result: any[] | Paginated<any>)') %> => {
<%- tplJsOrTs(
`    content.pagination = !result.data ? undefined : {`,
`    content.pagination = !isPaginated(result) ? undefined : {`
) %>
      total: result.total,
      limit: result.limit,
      skip: result.skip,
    }<%- sc %>

    return result<%- sc %>
  }<%- sc %>
}

<%- tplTsOnly([
  'function isPaginated<T>(it: T[] | Paginated<T>): it is Paginated<T> {',
  '  return !!(it as any).data;',
  '}',
  '',
]) -%>
<%- insertFragment('funcs') %>
<%- insertFragment('end') %>
