const internal = require("./internal")
const external = require("./external")
const csvParser = require("../../../utilities/csvParser")
const { isExternalTable, isSQL } = require("../../../integrations/utils")
const { getDatasourceParams } = require("../../../db/utils")
const { getAppDB } = require("@devlego/backend-core/context")
const { getTable, getAllInternalTables } = require("./utils")
const { events } = require("@devlego/backend-core")

function pickApi({ tableId, table }) {
  if (table && !tableId) {
    tableId = table._id
  }
  if (table && table.type === "external") {
    return external
  } else if (tableId && isExternalTable(tableId)) {
    return external
  }
  return internal
}

// covers both internal and external
exports.fetch = async function (ctx) {
  const db = getAppDB()

  const internal = await getAllInternalTables()

  const externalTables = await db.allDocs(
    getDatasourceParams("plus", {
      include_docs: true,
    })
  )

  const external = externalTables.rows.flatMap(tableDoc => {
    let entities = tableDoc.doc.entities
    if (entities) {
      return Object.values(entities).map(entity => ({
        ...entity,
        type: "external",
        sourceId: tableDoc.doc._id,
        sql: isSQL(tableDoc.doc),
      }))
    } else {
      return []
    }
  })

  ctx.body = [...internal, ...external]
}

exports.find = async function (ctx) {
  const tableId = ctx.params.tableId
  ctx.body = await getTable(tableId)
}

exports.save = async function (ctx) {
  const appId = ctx.appId
  const table = ctx.request.body
  const importFormat =
    table.dataImport && table.dataImport.csvString ? "csv" : undefined
  const savedTable = await pickApi({ table }).save(ctx)
  if (!table._id) {
    await events.table.created(savedTable)
  } else {
    await events.table.updated(savedTable)
  }
  if (importFormat) {
    await events.table.imported(savedTable, importFormat)
  }
  ctx.status = 200
  ctx.message = `Table ${table.name} saved successfully.`
  ctx.eventEmitter &&
    ctx.eventEmitter.emitTable(`table:save`, appId, savedTable)
  ctx.body = savedTable
}

exports.destroy = async function (ctx) {
  const appId = ctx.appId
  const tableId = ctx.params.tableId
  const deletedTable = await pickApi({ tableId }).destroy(ctx)
  await events.table.deleted(deletedTable)
  ctx.eventEmitter &&
    ctx.eventEmitter.emitTable(`table:delete`, appId, deletedTable)
  ctx.status = 200
  ctx.table = deletedTable
  ctx.body = { message: `Table ${tableId} deleted.` }
}

exports.bulkImport = async function (ctx) {
  const tableId = ctx.params.tableId
  await pickApi({ tableId }).bulkImport(ctx)
  // right now we don't trigger anything for bulk import because it
  // can only be done in the builder, but in the future we may need to
  // think about events for bulk items
  ctx.status = 200
  ctx.body = { message: `Bulk rows created.` }
}

exports.validateCSVSchema = async function (ctx) {
  // tableId being specified means its an import to an existing table
  const { csvString, schema = {}, tableId } = ctx.request.body
  let existingTable
  if (tableId) {
    existingTable = await getTable(tableId)
  }
  let result = await csvParser.parse(csvString, schema)
  if (existingTable) {
    result = csvParser.updateSchema({ schema: result, existingTable })
  }
  ctx.body = { schema: result }
}
