import React from 'react';
import { renderMessage } from './render';
import type { I18nMessageJsxFormatterArgs } from '../types';

interface I18nMessageTransform {
    name: string;
    pattern: RegExp;
    Wrapper: React.FC<{ children?: React.ReactNode }>;
}

const builtInTransforms: I18nMessageTransform[] = [
    {
        name: 'bold',
        pattern: /<b>(?<value>.*?)<\/b>/gim,
        Wrapper: ({ children }) => <b>{children}</b>,
    },
    {
        name: 'italic',
        pattern: /<i>(?<value>.*?)<\/i>/gim,
        Wrapper: ({ children }) => <i>{children}</i>,
    },
];

export const transformMessage = (message: string, args: I18nMessageJsxFormatterArgs = {}) => {
    const transforms = Object.entries(args)
        .filter((entry): entry is [string, React.FC] => typeof entry[1] === 'function')
        .map(
            ([name, Wrapper]): I18nMessageTransform => ({
                name,
                Wrapper,
                pattern: new RegExp(`{${name}}(?<value>.*?){/${name}}`, 'gim'),
            })
        );

    let transformedMessage = message;
    const transformedArgs = { ...args };

    [...builtInTransforms, ...transforms].forEach(({ Wrapper, pattern, name }) => {
        let result = pattern.exec(transformedMessage);

        while (result !== null) {
            const [match] = result;
            const key = `${name}:${result.index}`;

            const value = result.groups?.value;
            if (!value)
                throw new Error(
                    `The transform "${name}" does not define a capture group named "value".`
                );

            const transformed = transformMessage(value, transformedArgs);
            const child = renderMessage(transformed);

            transformedArgs[key] = <Wrapper {...result.groups}>{child}</Wrapper>;
            transformedMessage = transformedMessage.replace(match, `{${key}}`);

            result = pattern.exec(transformedMessage);
        }
    });

    return {
        message: transformedMessage,
        args: transformedArgs,
    };
};
