import { FormComponentType, InputDataType, Plugin, PluginResponseType, PluginType } from '../../types/index.js';
import { PUBLIC_INTEGRATIONS_LOGO_URL } from './constants.js';

const RedisPluginVersions = {
  V1: '0.0.1'
};

const CONNECTION_METHODS_AND_DISPLAY_NAMES: Record<string, string> = {
  url: 'Connection string',
  fields: 'Form'
};

const EXPIRE_OPTIONS_AND_PROPERTIES: Record<string, { description: string; displayName: string }> = {
  OPTION_UNSPECIFIED: { displayName: 'None', description: '' }, // NOTE (joey) do we really not have a better way of doing this?
  OPTION_NX: { displayName: 'NX', description: 'Set expiry only when the key has no expiry.' },
  OPTION_XX: { displayName: 'XX', description: 'Set expiry only when the key has an existing expiry' },
  OPTION_GT: { displayName: 'GT', description: 'Set expiry only when the new expiry is greater than current one' },
  OPTION_LT: { displayName: 'LT', description: 'Set expiry only when the new expiry is less than current one' }
};

// NOTE: (joey) is there an order we want these to be in?
// alphabetical vs most common vs a mix of both
const ACTION_DROPDOWN: { label?: string; value: string; children: { label: string; value: string; description?: string }[] }[] = [
  {
    value: 'raw',
    children: [{ label: 'Query', value: 'singleton', description: 'Send a raw Redis query.' }]
  },
  {
    value: 'structured',
    children: [
      { label: 'GET', value: 'get', description: 'Retrieve the value of a key.' },
      { label: 'SET', value: 'set', description: 'Set the value of a key.' },
      { label: 'DEL', value: 'del', description: 'Delete a key.' },
      { label: 'KEYS', value: 'keys', description: 'List all keys matching a pattern.' },
      { label: 'EXPIRE', value: 'expire', description: `Set a key's time to live in seconds.` },
      { label: 'TTL', value: 'ttl', description: 'Get the remaining time to live of a key.' },
      { label: 'MGET', value: 'mget', description: 'Retrieve values of multiple keys.' },
      { label: 'HGET', value: 'hget', description: 'Get the value from a hash field.' },
      { label: 'HMGET', value: 'hmget', description: 'Get the values of multiple hash fields.' },
      { label: 'HMGETALL', value: 'hmgetall', description: 'Get all fields and values in a hash.' },
      { label: 'HSET', value: 'hset', description: 'Set the value in a hash field.' },
      { label: 'HSETNX', value: 'hsetnx', description: `Set the value in a hash field if it doesn't exist.` },
      { label: 'HLEN', value: 'hlen', description: 'Get the number of fields in a hash.' },
      { label: 'HDEL', value: 'hdel', description: 'Delete a hash field.' },
      { label: 'HKEYS', value: 'hkeys', description: 'Get all field names in a hash.' },
      { label: 'HVALS', value: 'hvals', description: 'Get all values in a hash.' },
      { label: 'LINDEX', value: 'lindex', description: 'Get an element from a list by index.' },
      { label: 'LLEN', value: 'llen', description: 'Get the length of a list.' },
      { label: 'LPUSH', value: 'lpush', description: 'Add an element to a list.' },
      { label: 'LREM', value: 'lrem', description: 'Remove an element from a list.' },
      { label: 'LRANGE', value: 'lrange', description: 'Get the range of elements from a list.' },
      { label: 'SADD', value: 'sadd', description: 'Add a member to a set.' },
      { label: 'SCARD', value: 'scard', description: 'Get the number of members in a set.' },
      { label: 'SMEMBERS', value: 'smembers', description: 'Get all members in a set.' },
      { label: 'SISMEMBER', value: 'sismember', description: 'Check the membership of an item in a set.' },
      { label: 'SRANDMEMBER', value: 'srandmember', description: 'Get a random member from a set.' },
      { label: 'SREM', value: 'srem', description: 'Remove a member from a set.' },
      { label: 'ZADD', value: 'zadd', description: 'Add a member to a sorted set.' },
      { label: 'ZCARD', value: 'zcard', description: 'Get the number of members in a sorted set.' },
      { label: 'ZCOUNT', value: 'zcount', description: 'Count the members in a score range in sorted set.' },
      { label: 'ZRANGE', value: 'zrange', description: 'Get the members in a score range from sorted set.' },
      { label: 'ZRANK', value: 'zrank', description: 'Get the index rank of a member in sorted set.' },
      { label: 'ZREM', value: 'zrem', description: 'Remove a member from sorted set.' },
      { label: 'ZSCORE', value: 'zscore', description: 'Get the score of a member in sorted set.' }
    ]
  }
];

const makeDropdownItem = (value: string, displayName?: string, subText?: string) => {
  return {
    key: value,
    value: value,
    displayName: displayName ?? value,
    subText: subText ?? ''
  };
};

// TODO(docs-v2): no redis page exists in docs-v2; add one and restore docsUrl
export const RedisPlugin = generateRedisPlugin('redis', 'Redis', `${PUBLIC_INTEGRATIONS_LOGO_URL}/redis.png`);

function generateRedisPlugin(id: string, name: string, iconLocation: string, docsUrl?: string): Plugin {
  return {
    id,
    name,
    moduleName: 'RedisPlugin',
    modulePath: 'plugins/redis/RedisPlugin',
    iconLocation,
    docsUrl,
    type: PluginType.API,
    responseType: PluginResponseType.JSON,
    hasRawRequest: false,
    datasourceTemplate: {
      sections: [
        {
          name: 'main',
          items: [
            {
              label: 'Display name',
              name: 'name',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              placeholder: `${name} Prod`,
              rules: [{ required: true, message: 'Display name is required' }]
            },
            {
              label: 'Connection method',
              name: 'connection.connectionType.case',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DROPDOWN,
              initialValue: 'url',
              rules: [{ required: true }],
              options: Object.entries(CONNECTION_METHODS_AND_DISPLAY_NAMES).map(([value, displayName]) =>
                makeDropdownItem(value, displayName)
              )
            },
            {
              label: 'URI',
              name: 'connection.connectionType.value.urlString',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.PASSWORD, // since this can sometimes contain a password
              placeholder: `redis://[:password@]host[:port][/db-number]`,
              rules: [{ required: true, message: 'URI is required' }],
              display: {
                show: {
                  'connection.connectionType.case': ['url']
                }
              }
            },
            {
              label: 'Host',
              name: 'connection.connectionType.value.host',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              rules: [{ required: true, message: 'Host is required' }],
              display: {
                show: {
                  'connection.connectionType.case': ['fields']
                }
              }
            },
            {
              label: 'Port',
              name: 'connection.connectionType.value.port',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              initialValue: 6379,
              rules: [{ required: true, message: 'Port is required' }],
              display: {
                show: {
                  'connection.connectionType.case': ['fields']
                }
              }
            },
            {
              label: 'Database number',
              name: 'connection.connectionType.value.databaseNumber',
              startVersion: RedisPluginVersions.V1,
              dataType: InputDataType.NUMBER,
              componentType: FormComponentType.INPUT_TEXT,
              initialValue: 0,
              rules: [{ required: true, message: 'Database number is required' }],
              display: {
                show: {
                  'connection.connectionType.case': ['fields']
                }
              }
            },
            {
              label: 'Username (optional)',
              name: 'connection.connectionType.value.username',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              display: {
                show: {
                  'connection.connectionType.case': ['fields']
                }
              }
            },
            {
              label: 'Password (optional)',
              name: 'connection.connectionType.value.password',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.PASSWORD,
              display: {
                show: {
                  'connection.connectionType.case': ['fields']
                }
              }
            }
            // TODO re-enable this when we allow user to provide certs
            // {
            //   label: 'Enable SSL',
            //   name: 'connection.connectionType.value.enableSsl',
            //   startVersion: RedisPluginVersions.V1,
            //   componentType: FormComponentType.CHECKBOX,
            //   initialValue: true,
            //   display: {
            //     show: {
            //       'connection.connectionType.case': ['fields']
            //     }
            //   }
            // }
          ]
        }
      ]
    },
    actionTemplate: {
      sections: [
        {
          name: 'main',
          items: [
            {
              label: 'Action',
              name: 'commandType.value.action.case',
              secondaryName: 'commandType.case',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.ONEOF_ACTION_DROPDOWN,
              rules: [{ required: true }],
              initialValue: 'get',
              secondaryInitialValue: 'structured',
              actionOptions: ACTION_DROPDOWN
            },
            // raw command
            {
              label: 'Query',
              name: 'commandType.value.action.value.query',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              placeholder: 'SET myKey 1',
              display: {
                show: {
                  'commandType.case': ['raw']
                }
              },
              rules: [{ required: true, message: 'Query is required' }]
            },
            // structured commands
            {
              label: 'Key',
              name: 'commandType.value.action.value.key',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': [
                    'get',
                    'set',
                    'del',
                    'expire',
                    'ttl',
                    'hget',
                    'hmget',
                    'hgetall',
                    'hset',
                    'hsetnx',
                    'hlen',
                    'hdel',
                    'hkeys',
                    'hvals',
                    'lindex',
                    'llen',
                    'lpush',
                    'lrem',
                    'lrange',
                    'sadd',
                    'scard',
                    'smembers',
                    'sismember',
                    'srandmember',
                    'srem',
                    'zadd',
                    'zcard',
                    'zcount',
                    'zrange',
                    'zrank',
                    'zrem',
                    'zscore'
                  ]
                }
              },
              rules: [{ required: true, message: 'Key is required' }]
            },
            {
              label: 'Value',
              name: 'commandType.value.action.value.value',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['set', 'hset', 'hsentx', 'lpush', 'lrem', 'lrange']
                }
              },
              rules: [{ required: true, message: 'Value is required' }]
            },
            {
              label: 'Expiration (ms) (optional)',
              name: 'commandType.value.action.value.expirationMs',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['set']
                }
              }
            },
            {
              label: 'Pattern',
              name: 'commandType.value.action.value.pattern',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['keys']
                }
              },
              rules: [{ required: true, message: 'Pattern is required' }]
            },
            {
              label: 'Seconds',
              name: 'commandType.value.action.value.seconds',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['expire']
                }
              },
              rules: [{ required: true, message: 'Seconds is required' }]
            },
            {
              label: 'Option',
              name: 'commandType.value.action.value.option',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DROPDOWN,
              options: Object.entries(EXPIRE_OPTIONS_AND_PROPERTIES).map(([value, obj]) =>
                makeDropdownItem(value, obj.displayName, obj.description)
              ),
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['expire']
                }
              }
            },
            {
              label: 'Keys',
              name: 'commandType.value.action.value.keys',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['mget']
                }
              },
              rules: [{ required: true, message: 'Keys are required' }],
              tooltip: {
                markdownText: 'A comma-separated list of keys'
              }
            },
            {
              label: 'Field',
              name: 'commandType.value.action.value.field',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['hget', 'hset', 'hsetnx', 'hdel']
                }
              },
              rules: [{ required: true, message: 'Field is required' }]
            },
            {
              label: 'Fields',
              name: 'commandType.value.action.value.fields',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['hmget']
                }
              },
              rules: [{ required: true, message: 'Fields are required' }],
              tooltip: {
                markdownText: 'A comma-separated list of keys'
              }
            },
            {
              label: 'Index',
              name: 'commandType.value.action.value.index',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['lindex']
                }
              },
              rules: [{ required: true, message: 'Index is required' }]
            },
            // NOTE: (joey) we need 2 "Count" items since it is required for lrem but not for srandmember
            {
              label: 'Count',
              name: 'commandType.value.action.value.count',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['lrem']
                }
              },
              rules: [{ required: true, message: 'Count is required' }]
            },
            {
              label: 'Count (optional)',
              name: 'commandType.value.action.value.count',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['srandmember']
                }
              }
            },
            {
              label: 'Start',
              name: 'commandType.value.action.value.start',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['lrange']
                }
              },
              rules: [{ required: true, message: 'Start is required' }]
            },
            {
              label: 'Member',
              name: 'commandType.value.action.value.member',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['sadd', 'sismember', 'srem', 'zadd', 'zrank', 'zrem', 'zscore']
                }
              },
              rules: [{ required: true, message: 'Member is required' }]
            },
            {
              label: 'Score',
              name: 'commandType.value.action.value.score',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['zadd']
                }
              },
              rules: [{ required: true, message: 'Score is required' }]
            },
            {
              label: 'Min',
              name: 'commandType.value.action.value.min',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['zcount']
                }
              },
              rules: [{ required: true, message: 'Min is required' }]
            },
            {
              label: 'Max',
              name: 'commandType.value.action.value.max',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['zcount']
                }
              },
              rules: [{ required: true, message: 'Max is required' }]
            },
            {
              label: 'Start',
              name: 'commandType.value.action.value.min',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['zrange']
                }
              },
              rules: [{ required: true, message: 'Start is required' }]
            },
            {
              label: 'Stop',
              name: 'commandType.value.action.value.max',
              startVersion: RedisPluginVersions.V1,
              componentType: FormComponentType.INPUT_TEXT,
              dataType: InputDataType.NUMBER,
              display: {
                show: {
                  'commandType.case': ['structured'],
                  'commandType.value.action.case': ['zrange']
                }
              },
              rules: [{ required: true, message: 'Stop is required' }]
            }
          ]
        }
      ]
    }
  };
}
