// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#include "recorddirectory.h"
#include "translatormessage.h"

#include <QMap>

QT_BEGIN_NAMESPACE

const char *meta_id_key = "meta-id";

void RecordDirectory::recordMessage(const TranslatorMessage &msg)
{
    MessageItem mi{ msg.sourceText(), msg.context(),    msg.comment(),
                    QString(),        msg.lineNumber(), msg.startOffset(),
                    msg.endOffset(),  msg.isPlural(),   !msg.extra(meta_id_key).isEmpty() };
    if (const auto it = m_messages.find(mi); it != m_messages.end())
        mi.id = it->id;
    else if (QString id = msg.id(); id.isEmpty()) {
        mi.id = calculateId(msg);
        m_messages.emplace(mi);
    } else // this is only the case in verification
        mi.id = std::move(id);
    for (const TranslatorMessage::Reference &ref : msg.allReferences()) {
        auto ref_mi = std::make_shared<MessageItem>(mi);
        ref_mi->lineNo = ref.lineNumber();
        ref_mi->startOffset = ref.startOffset();
        ref_mi->endOffset = ref.endOffset();
        m_msgLocations[ref.fileName()].insert(std::move(ref_mi));
    }
}

void RecordDirectory::recordExistingId(const QString &id)
{
    m_existingIds.emplace(id);
}

void RecordDirectory::recordError(const QString &file, int line, const QString &error)
{
    if (auto &fileErrors = m_errors[file]; !fileErrors.contains(line))
        fileErrors[line] = "//ltext2id error: "_L1 + error;
}

void RecordDirectory::recordAddedLines(const QString &file, int fromLine, int addedLines)
{
    m_fileAddedLines[file].emplace(fromLine, addedLines);
}

int RecordDirectory::addedLines(const QString &file, int line) const
{
    int addedLines = 0;
    if (const auto fit = m_fileAddedLines.find(file); fit != m_fileAddedLines.cend()) {
        const auto &fileAddedLines = fit->second;
        auto itr = fileAddedLines.upper_bound(line);
        if (itr != fileAddedLines.cbegin()) {
            itr--;
            addedLines = itr->second;
        }
    }
    return addedLines;
}

bool RecordDirectory::containsFile(const QString &filename) const noexcept
{
    return m_msgLocations.contains(filename);
}

QString RecordDirectory::calculateId(const TranslatorMessage &msg) const
{
    QString id = msg.extra(meta_id_key);
    if (!id.isEmpty())
        return id;

    const QString &source = msg.sourceText();
    int words = 0;
    int index = 0;

    while (index < source.size()) {
        QChar c = source[index];
        bool word = false;
        while (!c.isLetterOrNumber()) {
            id += QChar('a' + c.unicode() % 32);
            word = true;
            if (++index == source.size())
                break;
            c = source[index];
        }
        if (word)
            words++;

        if (words == 2)
            break;
        id += c;
        index++;
    }

    if (!id.isEmpty() && id.front() == '-')
        id = msg.context() + id;
    else
        id = msg.context() + '-' + id;

    if (index < source.size() || !msg.comment().isEmpty())
        id += '-' + QString::number(qHash(source + msg.comment()) % 100000);

    if (m_existingIds.count(id))
        id += "_2"_L1;
    return id;
}

QString RecordDirectory::id(const TranslatorMessage &msg) const
{
    MessageItem mi{ msg.sourceText(), msg.context(), msg.comment(), QString() };
    if (const auto it = m_messages.find(mi); it != m_messages.end())
        return it->id;
    return {};
}

QT_END_NAMESPACE
