'use strict'

import AgiliteUtils from 'agilite-utils'
import Mongoose from 'agilite-utils/dist/mongoose'
import { MongoConfig, MongoUrlConfig } from './interfaces'

const connections: any = {}

export const generateMongoDbUrl = (config: MongoUrlConfig, dbName: string): string => {
  if (!config || !dbName || !config.protocol || !config.host) {
    throw new Error('Invalid configuration or missing parameters')
  }

  let url = config.protocol

  if (config.username && config.password) {
    url += `${config.username}:${config.password}@`
  }

  url += config.host
  url += `/${dbName}`

  if (config.urlSuffix) {
    url += config.urlSuffix
  }

  return url
}

export const getDbModel = async (
  id: string,
  dbName: string,
  mongoConfig: MongoConfig,
  modelName: string,
  modelSchema: Mongoose.Schema,
  returnConnection: boolean = false
) => {
  let conn: Mongoose.Connection
  let url: string
  let maxPoolSize: number | undefined = undefined
  let model: Mongoose.Model<any>

  try {
    if (!id || !dbName || !mongoConfig || !modelName || !modelSchema) {
      throw new Error('Invalid configuration or missing parameters')
    }

    maxPoolSize = mongoConfig.maxPoolSizes[id] || mongoConfig.maxPoolSizes['default']

    if (!connections[id]) {
      url = generateMongoDbUrl(mongoConfig.general, dbName) as string
      conn = await Mongoose.createConnection(url, { maxPoolSize }).asPromise()
      connections[id] = conn
    } else {
      conn = connections[id]
    }

    model = getModal(conn, modelName, modelSchema)

    if (returnConnection) {
      return { model, conn }
    } else {
      return model
    }
  } catch (e) {
    throw e
  }
}

export const getModal = (conn: Mongoose.Connection, modelName: string, modelSchema: Mongoose.Schema) => {
  if (conn.models[modelName]) return conn.model(modelName)
  return conn.model(modelName, modelSchema)
}

export const sendMail = (templateId, mailConfig, to, templateData) => {
  return new Promise<void>((resolve, reject) => {
    ;(async () => {
      let errMsg: any = null
      let result: any = null

      try {
        if (!mailConfig.enabled) return resolve()

        const data = {
          personalizations: [
            {
              to,
              bcc: mailConfig.bcc,
              dynamic_template_data: templateData
            }
          ],
          from: mailConfig.from,
          reply_to: mailConfig.reply_to,
          template_id: templateId
        }

        const config = {
          headers: mailConfig.headers,
          method: mailConfig.method,
          url: mailConfig.url,
          data
        }
        config.headers.authorization = `Bearer ${mailConfig.apiKey}`

        result = await AgiliteUtils.axiosRequest(config)
        resolve(result.data)
      } catch (e: any) {
        if (e.response) {
          errMsg = e.response.data
        } else if (e.message) {
          errMsg = e.message
        } else if (e.request) {
          errMsg = e.request
        } else {
          errMsg = e
        }

        reject(errMsg)
      }
    })()
  })
}

export const resetDbModelConnection = async (id: string): Promise<boolean> => {
  try {
    if (!id) {
      throw new Error('Invalid or missing id parameter')
    }

    if (connections[id]) {
      await connections[id].close()
      delete connections[id]
      return true
    }

    return false
  } catch (e) {
    throw e
  }
}
