const _ = require('lodash')
const graphHelper = require('../../helpers/graph')
const { v4: uuid } = require('uuid')

/* global WIKI */

module.exports = {
  Query: {
    async storageTargets (obj, args, context, info) {
      const dbTargets = await WIKI.models.storage.getTargets({ siteId: args.siteId })
      // targets = _.sortBy(targets.map(tgt => {
      //   const targetInfo = _.find(WIKI.data.storage, ['module', tgt.key]) || {}
      //   return {
      //     ...targetInfo,
      //     ...tgt,
      //     hasSchedule: (targetInfo.schedule !== false),
      //     syncInterval: targetInfo.syncInterval || targetInfo.schedule || 'P0D',
      //     syncIntervalDefault: targetInfo.schedule,
      //     config: _.sortBy(_.transform(tgt.config, (res, value, key) => {
      //       const configData = _.get(targetInfo.props, key, false)
      //       if (configData) {
      //         res.push({
      //           key,
      //           value: JSON.stringify({
      //             ...configData,
      //             value: (configData.sensitive && value.length > 0) ? '********' : value
      //           })
      //         })
      //       }
      //     }, []), 'key')
      //   }
      // }), ['title', 'key'])
      return _.sortBy(WIKI.storage.defs.map(md => {
        const dbTarget = dbTargets.find(tg => tg.module === md.key)
        return {
          id: dbTarget?.id ?? uuid(),
          isEnabled: dbTarget?.isEnabled ?? false,
          module: md.key,
          title: md.title,
          description: md.description,
          icon: md.icon,
          banner: md.banner,
          vendor: md.vendor,
          website: md.website,
          contentTypes: {
            activeTypes: dbTarget?.contentTypes?.activeTypes ?? md.contentTypes.defaultTypesEnabled,
            largeThreshold: dbTarget?.contentTypes?.largeThreshold ?? md.contentTypes.defaultLargeThreshold
          },
          assetDelivery: {
            isStreamingSupported: md?.assetDelivery?.isStreamingSupported ?? false,
            isDirectAccessSupported: md?.assetDelivery?.isDirectAccessSupported ?? false,
            streaming: dbTarget?.assetDelivery?.streaming ?? md?.assetDelivery?.defaultStreamingEnabled ?? false,
            directAccess: dbTarget?.assetDelivery?.directAccess ?? md?.assetDelivery?.defaultDirectAccessEnabled ?? false
          },
          versioning: {
            isSupported: md?.versioning?.isSupported ?? false,
            isForceEnabled: md?.versioning?.isForceEnabled ?? false,
            enabled: dbTarget?.versioning?.enabled ?? md?.versioning?.defaultEnabled ?? false
          },
          sync: {},
          status: {},
          setup: {
            handler: md?.setup?.handler,
            state: dbTarget?.state?.setup ?? 'notconfigured',
            values: md.setup?.handler
              ? _.transform(md.setup.defaultValues,
                (r, v, k) => {
                  r[k] = dbTarget?.config?.[k] ?? v
                }, {})
              : {}
          },
          config: _.transform(md.props, (r, v, k) => {
            const cfValue = dbTarget?.config?.[k] ?? v.default
            r[k] = {
              ...v,
              value: v.sensitive && cfValue ? '********' : cfValue,
              ...v.enum && {
                enum: v.enum.map(o => {
                  if (o.indexOf('|') > 0) {
                    const oParsed = o.split('|')
                    return {
                      value: oParsed[0],
                      label: oParsed[1]
                    }
                  } else {
                    return {
                      value: o,
                      label: o
                    }
                  }
                })
              }
            }
          }, {}),
          actions: md.actions
        }
      }), ['title'])
    }
  },
  Mutation: {
    async updateStorageTargets (obj, args, context) {
      WIKI.logger.debug(`Updating storage targets for site ${args.siteId}...`)
      try {
        const dbTargets = await WIKI.models.storage.getTargets({ siteId: args.siteId })
        for (const tgt of args.targets) {
          const md = _.find(WIKI.storage.defs, ['key', tgt.module])
          if (!md) {
            throw new Error('Invalid module key for non-existent storage target.')
          }

          const dbTarget = _.find(dbTargets, ['id', tgt.id])

          // -> Build update config object
          const updatedConfig = dbTarget?.config ?? {}
          if (tgt.config) {
            for (const [key, prop] of Object.entries(md.props)) {
              if (prop.readOnly) { continue }
              if (!Object.prototype.hasOwnProperty.call(tgt.config, key)) { continue }
              if (prop.sensitive && tgt.config[key] === '********') { continue }
              updatedConfig[key] = tgt.config[key]
            }
          }

          // -> Target doesn't exist yet in the DB, let's create it
          if (!dbTarget) {
            WIKI.logger.debug(`No existing DB configuration for module ${tgt.module}. Creating a new one...`)
            await WIKI.models.storage.query().insert({
              id: tgt.id,
              module: tgt.module,
              siteId: args.siteId,
              isEnabled: tgt.isEnabled ?? false,
              contentTypes: {
                activeTypes: tgt.contentTypes ?? md.contentTypes.defaultTypesEnabled ?? [],
                largeThreshold: tgt.largeThreshold ?? md.contentTypes.defaultLargeThreshold ?? '5MB'
              },
              assetDelivery: {
                streaming: tgt.assetDeliveryFileStreaming ?? md?.assetDelivery?.defaultStreamingEnabled ?? false,
                directAccess: tgt.assetDeliveryDirectAccess ?? md?.assetDelivery?.defaultDirectAccessEnabled ?? false
              },
              versioning: {
                enabled: tgt.useVersioning ?? md?.versioning?.defaultEnabled ?? false
              },
              state: {
                current: 'ok'
              },
              config: updatedConfig
            })
          } else {
            WIKI.logger.debug(`Updating DB configuration for module ${tgt.module}...`)
            await WIKI.models.storage.query().patch({
              isEnabled: tgt.isEnabled ?? dbTarget.isEnabled ?? false,
              contentTypes: {
                activeTypes: tgt.contentTypes ?? dbTarget?.contentTypes?.activeTypes ?? [],
                largeThreshold: tgt.largeThreshold ?? dbTarget?.contentTypes?.largeThreshold ?? '5MB'
              },
              assetDelivery: {
                streaming: tgt.assetDeliveryFileStreaming ?? dbTarget?.assetDelivery?.streaming ?? false,
                directAccess: tgt.assetDeliveryDirectAccess ?? dbTarget?.assetDelivery?.directAccess ?? false
              },
              versioning: {
                enabled: tgt.useVersioning ?? dbTarget?.versioning?.enabled ?? false
              },
              config: updatedConfig
            }).where('id', tgt.id)
          }
        }
        // await WIKI.models.storage.initTargets()
        return {
          status: graphHelper.generateSuccess('Storage targets updated successfully')
        }
      } catch (err) {
        return graphHelper.generateError(err)
      }
    },
    async setupStorageTarget (obj, args, context) {
      try {
        const tgt = await WIKI.models.storage.query().findById(args.targetId)
        if (!tgt) {
          throw new Error('Not storage target matching this ID')
        }
        const md = _.find(WIKI.storage.defs, ['key', tgt.module])
        if (!md) {
          throw new Error('No matching storage module installed.')
        }
        if (!await WIKI.models.storage.ensureModule(md.key)) {
          throw new Error('Failed to load storage module. Check logs for details.')
        }
        const result = await WIKI.storage.modules[md.key].setup(args.targetId, args.state)

        return {
          status: graphHelper.generateSuccess('Storage target setup step succeeded'),
          state: result
        }
      } catch (err) {
        return graphHelper.generateError(err)
      }
    },
    async destroyStorageTargetSetup (obj, args, context) {
      try {
        const tgt = await WIKI.models.storage.query().findById(args.targetId)
        if (!tgt) {
          throw new Error('Not storage target matching this ID')
        }
        const md = _.find(WIKI.storage.defs, ['key', tgt.module])
        if (!md) {
          throw new Error('No matching storage module installed.')
        }
        if (!await WIKI.models.storage.ensureModule(md.key)) {
          throw new Error('Failed to load storage module. Check logs for details.')
        }
        await WIKI.storage.modules[md.key].setupDestroy(args.targetId)

        return {
          status: graphHelper.generateSuccess('Storage target setup configuration destroyed succesfully.')
        }
      } catch (err) {
        return graphHelper.generateError(err)
      }
    },
    async executeStorageAction (obj, args, context) {
      try {
        await WIKI.models.storage.executeAction(args.targetKey, args.handler)
        return {
          status: graphHelper.generateSuccess('Action completed.')
        }
      } catch (err) {
        return graphHelper.generateError(err)
      }
    }
  }
}