/**
 * Represents a TipTap editor node structure.
 */
export interface TiptapNode {
    type: string;
    content?: TiptapNode[];
    text?: string;
    attrs?: {
        [key: string]: any;
    };
}

/**
 * Utility class for handling TipTap content conversions.
 * Provides methods to convert TipTap JSON content to HTML and plain text.
 */
export default class Content {
    /**
     * Converts TipTap raw JSON string content to plain text.
     * First converts to HTML, then strips HTML tags to produce plain text.
     *
     * @param content - The TipTap JSON string to convert
     * @returns The plain text representation of the content
     */
    static convertTipTapRawToText(content: string): string {
        const htmlContent: string = this.convertTiptapToHTMLFromString(content);
        return this.htmlToText(htmlContent);
    }

    /**
     * Converts HTML string to plain text by removing tags and normalizing whitespace.
     * Preserves paragraph structure by converting block elements to newlines.
     *
     * @param html - The HTML string to convert
     * @returns The plain text representation with preserved paragraph structure
     */
    static htmlToText(html: string): string {
        return html
            .replace(/<br\s*\/?>/gi, '\n')
            .replace(/<\/?(p|h[1-6]|div)(\s+[^>]*)?>/gi, '\n')
            .replace(/<\/?[^>]+(>|$)/g, '')
            .replace(/(\n\s*){2,}/g, '\n\n')
            .replace(/^\s+|\s+$|(?<=\s)\s+/g, '')
            .trim();
    }

    /**
     * Converts a TipTap JSON string to HTML.
     * Parses the JSON string and delegates to the node-based conversion method.
     *
     * @param jsonString - The TipTap JSON string to convert
     * @returns The HTML representation, or empty string if JSON is invalid
     */
    static convertTiptapToHTMLFromString(jsonString: string): string {
        let tiptapNode: TiptapNode;
        try {
            tiptapNode = JSON.parse(jsonString);
        } catch (error) {
            console.error('Invalid JSON string:', error);
            return '';
        }

        return this.convertTiptapToHTML(tiptapNode);
    }

    /**
     * Recursively converts a TipTap node structure to HTML.
     * Handles various node types including documents, paragraphs, headings, lists,
     * blockquotes, code blocks, and text with formatting attributes.
     *
     * @param node - The TipTap node to convert
     * @returns The HTML representation of the node and its children
     */
    static convertTiptapToHTML(node: TiptapNode): string {
        let html = '';

        switch (node.type) {
            case 'doc':
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                break;

            case 'paragraph':
                html += '<p>';
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                html += '</p>';
                break;

            case 'text':
                let formattedText = node.text || '';

                if (node.attrs) {
                    if (node.attrs.bold) {
                        formattedText = `<strong>${formattedText}</strong>`;
                    }
                    if (node.attrs.italic) {
                        formattedText = `<em>${formattedText}</em>`;
                    }
                    if (node.attrs.underline) {
                        formattedText = `<u>${formattedText}</u>`;
                    }
                    if (node.attrs.strike) {
                        formattedText = `<s>${formattedText}</s>`;
                    }
                    if (node.attrs.link) {
                        formattedText = `<a href="${node.attrs.link.href}">${formattedText}</a>`;
                    }
                }

                html += formattedText;
                break;

            case 'heading':
                const headingLevel = node.attrs?.level || 1;
                html += `<h${headingLevel}>`;
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                html += `</h${headingLevel}>`;
                break;

            case 'bulletList':
                html += '<ul>';
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                html += '</ul>';
                break;

            case 'orderedList':
                html += '<ol>';
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                html += '</ol>';
                break;

            case 'listItem':
                html += '<li>';
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                html += '</li>';
                break;

            case 'blockquote':
                html += '<blockquote>';
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                html += '</blockquote>';
                break;

            case 'codeBlock':
                html += '<pre><code>';
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                html += '</code></pre>';
                break;

            default:
                console.warn(`Unhandled node type: ${node.type}`);
                if (node.content) {
                    node.content.forEach((childNode: TiptapNode) => {
                        html += this.convertTiptapToHTML(childNode);
                    });
                }
                break;
        }

        return html;
    }
}
