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

const KinesisPluginVersions = {
  V1: '0.0.1'
};

// some constants to share with the UI
export const KINESIS_MODULE_NAME = 'KinesisPlugin';
export const OPERATION_TYPE_NAME = 'operationType';
export const OPERATION_TYPE_PUT = 'OPERATION_TYPE_PUT';
export const OPERATION_TYPE_GET = 'OPERATION_TYPE_GET';

const MESSAGES_PLACEHOLDER = `[
  {
    "id": 123,
    "company": "Superblocks!"
  },
  {
    "id": 456,
    "value": {
      "koala": "bear"
    }
  }
]`;

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

type DisplayInfo = { displayName: string; description: string };
const KINESIS_ACTIONS_AND_DISPLAY_NAMES: Record<string, DisplayInfo> = {
  OPERATION_TYPE_PUT: { displayName: 'Put', description: 'Put a number of records onto a Kinesis stream' },
  OPERATION_TYPE_GET: { displayName: 'Get', description: 'Stream records in from a Kinesis stream' }
};

const KINESIS_STREAM_IDENTIFIERS_AND_DISPLAY_NAMES: Record<string, string> = {
  STREAM_IDENTIFIER_STREAM_NAME: 'Stream name',
  STREAM_IDENTIFIER_STREAM_ARN: 'Stream ARN'
};

// descriptions from here: https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html
const KINESIS_SHARD_ITERATOR_TYPES_AND_DISPLAY_NAMES: Record<string, DisplayInfo> = {
  SHARD_ITERATOR_TYPE_LATEST: {
    displayName: 'Latest',
    description: 'Start reading just after the most recent record in the shard, so that you always read the most recent data in the shard'
  },
  SHARD_ITERATOR_TYPE_TRIM_HORIZON: {
    displayName: 'Trim Horizon',
    description: 'Start reading at the last untrimmed record in the shard in the system, which is the oldest data record in the shard'
  },
  SHARD_ITERATOR_TYPE_AT_TIMESTAMP: {
    displayName: 'Timestamp',
    description: 'Start reading from the position denoted by a specific time stamp'
  },
  SHARD_ITERATOR_TYPE_AT_SEQUENCE_NUMBER: {
    displayName: 'At sequence number',
    description: 'Start reading from the position denoted by a specific sequence number'
  },
  SHARD_ITERATOR_TYPE_AFTER_SEQUENCE_NUMBER: {
    displayName: 'After sequence number',
    description: 'Start reading right after the position denoted by a specific sequence number'
  }
};

const BASE_STREAM_IDENTIFIER = {
  label: 'Stream identifier',
  startVersion: KinesisPluginVersions.V1,
  componentType: FormComponentType.DROPDOWN,
  rules: [{ required: true }],
  initialValue: 'STREAM_IDENTIFIER_STREAM_NAME',
  options: Object.entries(KINESIS_STREAM_IDENTIFIERS_AND_DISPLAY_NAMES).map(([value, displayName]) => makeDropdownItem(value, displayName)),
  tooltip: {
    markdownText: 'Identify the stream to use'
  }
};

const BASE_STREAM_ARN = {
  label: 'ARN',
  startVersion: KinesisPluginVersions.V1,
  componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
  rules: [{ required: true }],
  placeholder: 'arn:aws:kinesis:us-east-1:123456789012:stream/my_stream',
  tooltip: {
    markdownText: 'The ARN of the stream to use'
  }
};

const BASE_STREAM_NAME = {
  label: 'Name',
  startVersion: KinesisPluginVersions.V1,
  componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
  rules: [{ required: true }],
  placeholder: 'my_stream',
  tooltip: {
    markdownText: 'The name of the stream to use'
  }
};

export const KinesisPlugin: Plugin = {
  id: 'kinesis',
  name: 'Amazon Kinesis',
  moduleName: KINESIS_MODULE_NAME,
  modulePath: 'plugins/kinesis/KinesisPlugin',
  iconLocation: `${PUBLIC_INTEGRATIONS_LOGO_URL}/kinesis.png`,
  // TODO(docs-v2): no kinesis page exists in docs-v2; add one or remove this line
  docsUrl: undefined,
  type: PluginType.API,
  responseType: PluginResponseType.JSON,
  hasRawRequest: false,
  hasMetadata: true,
  isStreamable: true,
  datasourceTemplate: {
    sections: [
      {
        name: 'main',
        items: [
          {
            label: 'Display name',
            name: 'name',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.INPUT_TEXT,
            placeholder: 'Amazon Kinesis Prod',
            rules: [{ required: true, message: 'Display name is required' }]
          },
          {
            label: 'Region',
            name: 'connection.awsConfig.region',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.INPUT_TEXT,
            placeholder: 'us-east-1',
            rules: [{ required: true, message: 'Region is required' }]
          },
          {
            label: 'Access key ID',
            name: 'connection.awsConfig.auth.accessKeyId',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.INPUT_TEXT,
            rules: [{ required: true, message: 'Access key ID is required' }]
          },
          {
            label: 'Secret key',
            name: 'connection.awsConfig.auth.secretKey',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.INPUT_TEXT,
            dataType: InputDataType.PASSWORD,
            rules: [{ required: true, message: 'Secret key is required' }]
          },
          {
            label: 'Endpoint (optional)',
            name: 'connection.awsConfig.endpoint',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.INPUT_TEXT,
            placeholder: 'kinesis.us-east-1.amazonaws.com:4566',
            tooltip: {
              markdownText:
                'Specify the data stream endpoint to connect to. [Read more](https://docs.aws.amazon.com/general/latest/gr/ak.html)'
            }
          }
        ]
      }
    ]
  },
  actionTemplate: {
    sections: [
      {
        name: 'actionSelect',
        items: [
          {
            label: 'Action',
            name: 'operationType',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.DROPDOWN,
            rules: [{ required: true }],
            // logic in the front-end will choose the right default based on
            // the context. we should bring that in the form.
            initialValue: 'OPERATION_TYPE_PUT',
            options: Object.entries(KINESIS_ACTIONS_AND_DISPLAY_NAMES).map(([value, displayInfo]) =>
              makeDropdownItem(value, displayInfo.displayName, displayInfo.description)
            )
          }
        ]
      },
      {
        name: 'streamIdentifier',
        items: [
          // PUT
          {
            name: 'put.streamIdentifierType',
            display: {
              show: {
                operationType: ['OPERATION_TYPE_PUT']
              }
            },
            ...BASE_STREAM_IDENTIFIER
          } as FormItem,
          {
            name: 'put.streamName',
            display: {
              show: {
                operationType: ['OPERATION_TYPE_PUT'],
                'put.streamIdentifierType': ['STREAM_IDENTIFIER_STREAM_NAME']
              }
            },
            ...BASE_STREAM_NAME
          } as FormItem,
          {
            name: 'put.streamArn',
            display: {
              show: {
                operationType: ['OPERATION_TYPE_PUT'],
                'put.streamIdentifierType': ['STREAM_IDENTIFIER_STREAM_ARN']
              }
            },
            ...BASE_STREAM_ARN
          } as FormItem,
          // GET
          {
            name: 'get.streamIdentifierType',
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET']
              }
            },
            ...BASE_STREAM_IDENTIFIER
          } as FormItem,
          {
            name: 'get.streamName',
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET'],
                'get.streamIdentifierType': ['STREAM_IDENTIFIER_STREAM_NAME']
              }
            },
            ...BASE_STREAM_NAME
          } as FormItem,
          {
            name: 'get.streamArn',
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET'],
                'get.streamIdentifierType': ['STREAM_IDENTIFIER_STREAM_ARN']
              }
            },
            ...BASE_STREAM_ARN
          } as FormItem
        ]
      },
      {
        name: 'main',
        items: [
          // put
          {
            label: 'Partition Key',
            name: 'put.partitionKey',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
            rules: [{ required: true, message: 'Partition key is required' }],
            display: {
              show: {
                operationType: ['OPERATION_TYPE_PUT']
              }
            },
            tooltip: {
              markdownText: 'Used to group data by shard within a stream'
            }
          },
          {
            label: 'Messages',
            name: 'put.data',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.CODE_EDITOR,
            rules: [{ required: true, message: 'Messages are required' }],
            language: EditorLanguage.JSON,
            tooltip: {
              markdownText: 'A JSON array of messages to put'
            },
            placeholder: MESSAGES_PLACEHOLDER,
            display: {
              show: {
                operationType: ['OPERATION_TYPE_PUT']
              }
            }
          },
          // get
          {
            label: 'Shard ID',
            name: 'get.shardId',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
            rules: [{ required: true, message: 'Shard ID is required' }],
            placeholder: 'shardId-000000000001',
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET']
              }
            },
            tooltip: {
              markdownText: 'The shard ID to use when getting data'
            }
          },
          {
            label: 'Shard iterator type',
            name: 'get.shardIteratorType',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.DROPDOWN,
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET']
              }
            },
            rules: [{ required: true }],
            initialValue: 'SHARD_ITERATOR_TYPE_LATEST',
            options: Object.entries(KINESIS_SHARD_ITERATOR_TYPES_AND_DISPLAY_NAMES).map(([value, displayInfo]) =>
              makeDropdownItem(value, displayInfo.displayName, displayInfo.description)
            ),
            tooltip: {
              markdownText: 'Identify the point you would like to get from'
            }
          },
          {
            label: 'Starting sequence number',
            name: 'get.startingSequenceNumber',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
            rules: [{ required: true, message: 'Starting sequence number is required' }],
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET'],
                'get.shardIteratorType': ['SHARD_ITERATOR_TYPE_AT_SEQUENCE_NUMBER', 'SHARD_ITERATOR_TYPE_AFTER_SEQUENCE_NUMBER']
              }
            },
            tooltip: {
              // https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html
              markdownText: 'The sequence number of the data record in the shard from which to start reading'
            }
          },
          {
            label: 'Timestamp',
            name: 'get.timestamp',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
            rules: [{ required: true, message: 'Timestamp is required' }],
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET'],
                'get.shardIteratorType': ['SHARD_ITERATOR_TYPE_AT_TIMESTAMP']
              }
            },
            tooltip: {
              // https://docs.aws.amazon.com/kinesis/latest/APIReference/API_GetShardIterator.html
              markdownText: 'The ISO-formatted timestamp of the data record from which to start reading'
            }
          },
          {
            label: 'Limit',
            name: 'get.limit',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
            rules: [{ required: true, message: 'Limit is required' }],
            dataType: InputDataType.NUMBER,
            initialValue: 10,
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET']
              }
            },
            tooltip: {
              markdownText: 'The maximum number of messages to get in each polling cycle'
            }
          },
          {
            label: 'Polling cooldown ms',
            name: 'get.pollingCooldownMs',
            startVersion: KinesisPluginVersions.V1,
            componentType: FormComponentType.DYNAMIC_INPUT_TEXT,
            rules: [{ required: true, message: 'Polling cooldown ms is required' }],
            dataType: InputDataType.NUMBER,
            initialValue: 1000,
            display: {
              show: {
                operationType: ['OPERATION_TYPE_GET']
              }
            },
            tooltip: {
              markdownText: 'The amount of time in milliseconds to wait between each polling cycle'
            }
          }
        ]
      }
    ]
  }
};
