import * as client from '@botpress/client'
import * as sdk from '@botpress/sdk'
import * as errors from '../errors'
import * as utils from '../utils'
import * as types from './types'

export const prepareCreatePluginBody = async (plugin: sdk.PluginDefinition): Promise<types.CreatePluginRequestBody> => {
  const base = `Failed to convert ZUI to JSON schema for plugin ${plugin.name}`
  return {
    name: plugin.name,
    version: plugin.version,
    title: 'title' in plugin ? plugin.title : undefined,
    description: 'description' in plugin ? plugin.description : undefined,
    user: {
      tags: plugin.user?.tags ?? {},
    },
    conversation: {
      tags: plugin.conversation?.tags ?? {},
    },
    message: {
      tags: plugin.message?.tags ?? {},
    },
    configuration: plugin.configuration
      ? {
          ...plugin.configuration,
          schema: await utils.schema
            .mapZodToJsonSchema(plugin.configuration, {
              useLegacyZuiTransformer: plugin.__advanced?.useLegacyZuiTransformer,
              toJSONSchemaOptions: plugin.__advanced?.toJSONSchemaOptions,
            })
            .catch((thrown) => {
              throw errors.BotpressCLIError.wrap(thrown, `${base} for configuration`)
            }),
        }
      : undefined,
    events: plugin.events
      ? await utils.records.mapValuesAsync(plugin.events, async (event, eventName) => ({
          ...event,
          schema: await utils.schema
            .mapZodToJsonSchema(event, {
              useLegacyZuiTransformer: plugin.__advanced?.useLegacyZuiTransformer,
              toJSONSchemaOptions: plugin.__advanced?.toJSONSchemaOptions,
            })
            .catch((thrown) => {
              throw errors.BotpressCLIError.wrap(thrown, `${base} for event ${eventName}`)
            }),
        }))
      : undefined,
    actions: plugin.actions
      ? await utils.records.mapValuesAsync(plugin.actions, async (action, actionName) => ({
          ...action,
          input: {
            ...action.input,
            schema: await utils.schema
              .mapZodToJsonSchema(action.input, {
                useLegacyZuiTransformer: plugin.__advanced?.useLegacyZuiTransformer,
                toJSONSchemaOptions: plugin.__advanced?.toJSONSchemaOptions,
              })
              .catch((thrown) => {
                throw errors.BotpressCLIError.wrap(thrown, `${base} for action ${actionName} input`)
              }),
          },
          output: {
            ...action.output,
            schema: await utils.schema
              .mapZodToJsonSchema(action.output, {
                useLegacyZuiTransformer: plugin.__advanced?.useLegacyZuiTransformer,
                toJSONSchemaOptions: plugin.__advanced?.toJSONSchemaOptions,
              })
              .catch((thrown) => {
                throw errors.BotpressCLIError.wrap(thrown, `${base} for action ${actionName} output`)
              }),
          },
        }))
      : undefined,
    states: plugin.states
      ? (utils.records.filterValues(
          await utils.records.mapValuesAsync(plugin.states, async (state, stateName) => ({
            ...state,
            schema: await utils.schema
              .mapZodToJsonSchema(state, {
                useLegacyZuiTransformer: plugin.__advanced?.useLegacyZuiTransformer,
                toJSONSchemaOptions: plugin.__advanced?.toJSONSchemaOptions,
              })
              .catch((thrown) => {
                throw errors.BotpressCLIError.wrap(thrown, `${base} for state ${stateName}`)
              }),
          })),
          ({ type }) => type !== 'workflow'
        ) as types.CreatePluginRequestBody['states'])
      : undefined,
    attributes: plugin.attributes,
  }
}

export const prepareUpdatePluginBody = (
  localPlugin: types.UpdatePluginRequestBody,
  remotePlugin: client.Plugin
): types.UpdatePluginRequestBody => {
  const actions = utils.attributes.prepareAttributeUpdateBody({
    localItems: utils.records.setNullOnMissingValues(localPlugin.actions, remotePlugin.actions),
    remoteItems: remotePlugin.actions,
  })
  const events = utils.attributes.prepareAttributeUpdateBody({
    localItems: utils.records.setNullOnMissingValues(localPlugin.events, remotePlugin.events),
    remoteItems: remotePlugin.events,
  })
  const states = utils.records.setNullOnMissingValues(localPlugin.states, remotePlugin.states)

  const attributes = utils.records.setNullOnMissingValues(localPlugin.attributes, remotePlugin.attributes)

  const dependencies: types.UpdatePluginRequestBody['dependencies'] = {
    integrations: utils.records.setNullOnMissingValues(
      localPlugin.dependencies?.integrations,
      remotePlugin.dependencies?.integrations
    ),
    interfaces: utils.records.setNullOnMissingValues(
      localPlugin.dependencies?.interfaces,
      remotePlugin.dependencies?.interfaces
    ),
  }

  // TODO: set null to conversation, user and message tags that are removed

  return {
    ...localPlugin,
    actions,
    events,
    states,
    attributes,
    dependencies,
  }
}
