#ifdef WITH_RIVE_TEXT
#include "rive/text/fully_shaped_text.hpp"
#include "rive/text/text.hpp"

using namespace rive;

void FullyShapedText::shape(Span<Unichar> text,
                            Span<TextRun> runs,
                            TextSizing sizing,
                            float maxWidth,
                            float maxHeight,
                            TextAlign alignment,
                            TextWrap wrap,
                            TextOrigin origin,
                            TextOverflow overflow,
                            float paragraphSpacing)
{
    m_paragraphs = runs[0].font->shapeText(text, runs);
    m_glyphLookup.compute(text, m_paragraphs);

    m_paragraphLines =
        Text::BreakLines(m_paragraphs,
                         sizing == TextSizing::autoWidth ? -1.0f : maxWidth,
                         alignment,
                         wrap);
    m_orderedLines.clear();
    m_ellipsisRun = {};

    // build render styles.
    if (m_paragraphs.empty())
    {
        m_bounds = AABB(0.0f, 0.0f, 0.0f, 0.0f);
        return;
    }

    // Build up ordered runs as we go.
    int32_t paragraphIndex = 0;
    float y = 0.0f;
    float minY = 0.0f;
    float measuredWidth = 0.0f;
    if (origin == TextOrigin::baseline && !m_paragraphLines.empty() &&
        !m_paragraphLines[0].empty())
    {
        y -= m_paragraphLines[0][0].baseline;
        minY = y;
    }

    int ellipsisLine = -1;
    bool isEllipsisLineLast = false;
    // Find the line to put the ellipsis on (line before the one that
    // overflows).
    bool wantEllipsis =
        overflow == TextOverflow::ellipsis && sizing == TextSizing::fixed;

    int lastLineIndex = -1;
    for (const SimpleArray<GlyphLine>& paragraphLines : m_paragraphLines)
    {
        const Paragraph& paragraph = m_paragraphs[paragraphIndex++];
        for (const GlyphLine& line : paragraphLines)
        {
            const GlyphRun& endRun = paragraph.runs[line.endRunIndex];
            const GlyphRun& startRun = paragraph.runs[line.startRunIndex];
            float width = endRun.xpos[line.endGlyphIndex] -
                          startRun.xpos[line.startGlyphIndex];
            if (width > measuredWidth)
            {
                measuredWidth = width;
            }
            lastLineIndex++;
            if (wantEllipsis && y + line.bottom <= maxHeight)
            {
                ellipsisLine++;
            }
        }

        if (!paragraphLines.empty())
        {
            y += paragraphLines.back().bottom;
        }
        y += paragraphSpacing;
    }
    if (wantEllipsis && ellipsisLine == -1)
    {
        // Nothing fits, just show the first line and ellipse it.
        ellipsisLine = 0;
    }
    isEllipsisLineLast = lastLineIndex == ellipsisLine;

    int32_t lineIndex = 0;
    m_bounds =
        AABB(0.0f, minY, measuredWidth, std::max(minY, y - paragraphSpacing));

    y = 0;
    if (origin == TextOrigin::baseline && !m_paragraphLines.empty() &&
        !m_paragraphLines[0].empty())
    {
        y -= m_paragraphLines[0][0].baseline;
    }
    paragraphIndex = 0;

    for (const SimpleArray<GlyphLine>& paragraphLines : m_paragraphLines)
    {
        const Paragraph& paragraph = m_paragraphs[paragraphIndex++];
        for (const GlyphLine& line : paragraphLines)
        {
            switch (overflow)
            {
                case TextOverflow::hidden:
                    if (sizing == TextSizing::fixed &&
                        y + line.bottom > maxHeight)
                    {
                        return;
                    }
                    break;
                case TextOverflow::clipped:
                    if (sizing == TextSizing::fixed && y + line.top > maxHeight)
                    {
                        return;
                    }
                    break;
                default:
                    break;
            }

            m_orderedLines.emplace_back(OrderedLine(paragraph,
                                                    line,
                                                    maxWidth,
                                                    ellipsisLine == lineIndex,
                                                    isEllipsisLineLast,
                                                    &m_ellipsisRun,
                                                    y + line.baseline));

            if (lineIndex == ellipsisLine)
            {
                return;
            }
            lineIndex++;
        }
        if (!paragraphLines.empty())
        {
            y += paragraphLines.back().bottom;
        }
        y += paragraphSpacing;
    }
    return;
}
#endif