/*
    SPDX-FileCopyrightText: 2026 Igor Mironchik <igor.mironchik@gmail.com>
    SPDX-License-Identifier: MIT
*/

#ifndef MD4QT_MD_BLOCKQUOTE_PARSER_H_INCLUDED
#define MD4QT_MD_BLOCKQUOTE_PARSER_H_INCLUDED

// md4qt include.
#include "block_parser.h"
#include "constants.h"
#include "utils.h"

// Qt include.
#include <QHash>

namespace MD
{

/*!
 * \class MD::BlockquoteParser
 * \inmodule md4qt
 * \inheaderfile md4qt/blockquote_parser.h
 *
 * \brief Blockquote parser.
 *
 * Blockquote parser.
 */
class BlockquoteParser : public BlockParser
{
public:
    explicit BlockquoteParser(Parser *parser);
    ~BlockquoteParser() override = default;

    /*!
     * Returns check state for the current line and block type. This method should return BlockState::None if
     * this string is not handled by him. If this block parser knows how to handle the current line it should
     * return BlockState::Continue or BlockState::Stop.
     *
     * \a currentLine Current processing line.
     *
     * \a stream Stream of the lines.
     *
     * \a doc Current document.
     *
     * \a ctx Current parsing context.
     *
     * \a path Path to Markdown file.
     *
     * \a fileName File name of the Markdown file.
     *
     * \a checkWithoutProcessing Flags to don't do real processing, just check this parser handles this line.
     */
    BlockState check(Line &currentLine,
                     TextStream &stream,
                     QSharedPointer<Document> doc,
                     Context &ctx,
                     const QString &path,
                     const QString &fileName,
                     bool checkWithoutProcessing = false) override;

    /*!
     * Continue check. If checking knows that block is finished it should return BlockState::Stop.
     *
     * \a currentLine Current processing line.
     *
     * \a stream Stream of the lines.
     *
     * \a doc Current document.
     *
     * \a ctx Current parsing context.
     *
     * \a path Path to Markdown file.
     *
     * \a fileName File name of the Markdown file.
     */
    BlockState continueCheck(Line &currentLine,
                             TextStream &stream,
                             QSharedPointer<Document> doc,
                             Context &ctx,
                             const QString &path,
                             const QString &fileName) override;

    /*!
     * Process block - do actual parsing and populating MD::Document. If starting empty line is not a subject
     * for work for this kind of block this method should just skip the line.
     *
     * This method should call himself on all children contexts till block finish.
     *
     * \a currentLine Current processing line.
     *
     * \a stream Stream of the lines.
     *
     * \a doc Document.
     *
     * \a parent Parent of this block.
     *
     * \a ctx Current parsing context.
     *
     * \a path Path to Markdown file.
     *
     * \a fileName File name of the Markdown file.
     *
     * \a linksToParse List of links for further parsing.
     */
    BlockState process(Line &currentLine,
                       TextStream &stream,
                       QSharedPointer<Document> doc,
                       QSharedPointer<Block> parent,
                       Context &ctx,
                       const QString &path,
                       const QString &fileName,
                       QStringList &linksToParse) override;

    /*!
     * Reset state of the block parser for further reuse.
     *
     * \a ctx Context.
     */
    void reset(Context &ctx) override;

    /*!
     * Reset state of the block parser for further reuse.
     */
    void resetOnAllContexts() override;

    /*!
     * Return whether this kind of block may break a paragraph.
     *
     * \a line Line.
     *
     * \a stream Stream.
     *
     * \a doc Document.
     *
     * \a ctx Context.
     */
    bool mayBreakParagraph(Line &line,
                           TextStream &stream,
                           QSharedPointer<Document> doc,
                           Context &ctx) const override;

    /*!
     * Returns current block.
     *
     * \a ctx Context.
     */
    QSharedPointer<Block> currentBlock(const Context &ctx) const override;

private:
    void processGreaterSign(Line &currentLine,
                            Context &ctx);

    inline bool isBlockquote(Line &currentLine,
                             const Context &ctx) const
    {
        const auto st = currentLine.currentState();
        skipSpaces(currentLine);

        const auto res = (ctx.isInIndent(currentLine.column()) && currentLine.currentChar() == s_greaterSignChar);

        if (!res) {
            currentLine.restoreState(&st);
        }

        return res;
    }

    inline bool isBlockquoteOrLazyLine(Line &currentLine,
                                       const Context &ctx) const
    {
        return (isBlockquote(currentLine, ctx) || ctx.isLazyLine(currentLine.lineNumber()));
    }

private:
    QHash<const Context *, QSharedPointer<Blockquote>> m_quotes;
}; // class BlockquoteParser

} /* namespace MD */

#endif // MD4QT_MD_BLOCKQUOTE_PARSER_H_INCLUDED
