// @flow

import { Component } from 'react';

/**
 * {@code AbstractCaptions} properties.
 */
export type AbstractCaptionsProps = {

    /**
     * Whether local participant is requesting to see subtitles.
     */
    _requestingSubtitles: boolean,

    /**
     * Transcript texts formatted with participant's name and final content.
     * Mapped by id just to have the keys for convenience during the rendering
     * process.
     */
    _transcripts: Map<string, string>
};

/**
 * Abstract React {@code Component} which can display speech-to-text results
 * from Jigasi as subtitles.
 */
export class AbstractCaptions<P: AbstractCaptionsProps>
    extends Component<P> {

    /**
     * Implements React's {@link Component#render()}.
     *
     * @inheritdoc
     * @returns {React$Element}
     */
    render() {
        const { _requestingSubtitles, _transcripts } = this.props;

        if (!_requestingSubtitles || !_transcripts.size) {
            return null;
        }

        const paragraphs = [];

        for (const [ id, text ] of _transcripts) {
            paragraphs.push(this._renderParagraph(id, text));
        }

        return this._renderSubtitlesContainer(paragraphs);
    }

    /**
     * Renders the transcription text.
     *
     * @abstract
     * @param {string} id - The ID of the transcript message from which the
     * {@code text} has been created.
     * @param {string} text - Subtitles text formatted with the participant's
     * name.
     * @protected
     * @returns {React$Element} - The React element which displays the text.
     */
    _renderParagraph: (id: string, text: string) => React$Element<*>;

    /**
     * Renders the subtitles container.
     *
     * @abstract
     * @param {Array<React$Element>} paragraphs - An array of elements created
     * for each subtitle using the {@link _renderParagraph} method.
     * @protected
     * @returns {React$Element} - The subtitles container.
     */
    _renderSubtitlesContainer: (Array<React$Element<*>>) => React$Element<*>;
}

/**
 * Formats the transcript messages into text by prefixing participant's name to
 * avoid duplicating the effort on platform specific component.
 *
 * @param {Object} state - The redux state.
 * @private
 * @returns {Map<string, string>} - Formatted transcript subtitles mapped by
 * transcript message IDs.
 */
function _constructTranscripts(state: Object): Map<string, string> {
    const { _transcriptMessages } = state['features/subtitles'];
    const transcripts = new Map();

    for (const [ id, transcriptMessage ] of _transcriptMessages) {
        if (transcriptMessage) {
            let text = `${transcriptMessage.participantName}: `;

            if (transcriptMessage.final) {
                text += transcriptMessage.final;
            } else {
                const stable = transcriptMessage.stable || '';
                const unstable = transcriptMessage.unstable || '';

                text += stable + unstable;
            }

            transcripts.set(id, text);
        }
    }

    return transcripts;
}

/**
 * Maps the transcriptionSubtitles in the redux state to the associated props of
 * {@code AbstractCaptions}.
 *
 * @param {Object} state - The redux state.
 * @private
 * @returns {{
 *     _requestingSubtitles: boolean,
 *     _transcripts: Map<string, string>
 * }}
 */
export function _abstractMapStateToProps(state: Object) {
    const { _requestingSubtitles } = state['features/subtitles'];

    return {
        _requestingSubtitles,
        _transcripts: _constructTranscripts(state)
    };
}
