#include "specificationpcbtablemodel.h"
#include "componentmodel.h"
#include "../view/pagebreakconfirmationdialog.h"
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QColor>
#include <QApplication>
#include <QFont>
#include <QFontMetrics>
#include <QSet>
#include <QPair>
#include <QBrush>

// Статические константы
const QStringList SpecificationPCBTableModel::DEFAULT_HEADERS = {
    "Формат", "Зона", "Поз.", "Обозначение", "Наименование", "Кол.", "Примечание"
};

SpecificationPCBTableModel::SpecificationPCBTableModel(QObject *parent)
    : QAbstractTableModel(parent)
    , m_columnMappings(DEFAULT_HEADERS)
{
    qDebug() << "SpecificationPCBTableModel: Конструктор";
}

int SpecificationPCBTableModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }
    return m_rows.size();
}

int SpecificationPCBTableModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid()) {
        return 0;
    }
    return COLUMN_COUNT;
}

QVariant SpecificationPCBTableModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() >= m_rows.size() || index.column() >= COLUMN_COUNT) {
        return QVariant();
    }
    
    const SpecificationPCBRowData &rowData = m_rows[index.row()];
    
    if (role == Qt::DisplayRole || role == Qt::EditRole) {
        switch (index.column()) {
        case 0: return rowData.format.value;
        case 1: return rowData.zone.value;
        case 2: return rowData.position.value;
        case 3: return rowData.designation.value;
        case 4: return rowData.name.value;
        case 5: return rowData.quantity.value;
        case 6: return rowData.note.value;
        default: return QVariant();
        }
    }
    
    if (role == Qt::BackgroundRole) {
        if (rowData.isHeader) {
            return QBrush(QColor(200, 200, 200));
        } else {
            // Проверяем переполнение ячейки (используем приблизительную ширину колонки)
            // Приблизительные ширины колонок для SpecificationPCB (в пикселях)
            static const qreal columnWidths[] = {60, 50, 80, 150, 200, 60, 150}; // Формат, Зона, Поз., Обозначение, Наименование, Кол., Примечание
            qreal columnWidth = (index.column() < 7) ? columnWidths[index.column()] : 150;
            
            // Проверяем переполнение ячейки (используем информацию из PDF)
            QPair<int, int> cellKey(index.row(), index.column());
            if (m_overflowCells.contains(cellKey)) {
                // Подсвечиваем красным, если ячейка переполнена (помечена из PDF)
                return QBrush(QColor(255, 200, 200)); // Светло-красный
            }
            
            // Чередуем оттенки фона для разных страниц
            // Нечетные страницы - светло-голубой, четные - светло-желтый
            if (rowData.pageNumber % 2 == 1) {
                return QBrush(QColor(240, 248, 255)); // AliceBlue - для нечетных страниц
            } else {
                return QBrush(QColor(255, 255, 240)); // Ivory - для четных страниц
            }
        }
    }
    
    if (role == Qt::TextAlignmentRole) {
        return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
    } else if (role == Qt::FontRole) {
        QFont font;
        bool isBold = false;
        bool isUnderline = false;
        
        // Проверяем свойства ячейки
        switch (index.column()) {
        case 0:
            isBold = rowData.format.isHeader;
            isUnderline = rowData.format.isUnderline;
            break;
        case 1:
            isBold = rowData.zone.isHeader;
            isUnderline = rowData.zone.isUnderline;
            break;
        case 2:
            isBold = rowData.position.isHeader;
            isUnderline = rowData.position.isUnderline;
            break;
        case 3:
            isBold = rowData.designation.isHeader;
            isUnderline = rowData.designation.isUnderline;
            break;
        case 4:
            isBold = rowData.name.isHeader;
            isUnderline = rowData.name.isUnderline;
            break;
        case 5:
            isBold = rowData.quantity.isHeader;
            isUnderline = rowData.quantity.isUnderline;
            break;
        case 6:
            isBold = rowData.note.isHeader;
            isUnderline = rowData.note.isUnderline;
            break;
        default:
            break;
        }
        
        if (isBold) {
            font.setBold(true);
        }
        if (isUnderline) {
            font.setUnderline(true);
        }
        
        if (isBold || isUnderline) {
            return font;
        }
    } else if (role == Qt::UserRole) {
        // Возвращаем структуру ячейки для дополнительной информации
        switch (index.column()) {
        case 0: return QVariant::fromValue(rowData.format);
        case 1: return QVariant::fromValue(rowData.zone);
        case 2: return QVariant::fromValue(rowData.position);
        case 3: return QVariant::fromValue(rowData.designation);
        case 4: return QVariant::fromValue(rowData.name);
        case 5: return QVariant::fromValue(rowData.quantity);
        case 6: return QVariant::fromValue(rowData.note);
        default: return QVariant();
        }
    }
    
    return QVariant();
}

QVariant SpecificationPCBTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole) {
        if (orientation == Qt::Horizontal) {
            if (section < DEFAULT_HEADERS.size()) {
                return DEFAULT_HEADERS[section];
            }
        } else {
            // Вертикальные заголовки - номера строк с указанием страницы
            if (section < m_rows.size()) {
                const SpecificationPCBRowData &row = m_rows[section];
                return QString("%1 (стр. %2)").arg(section + 1).arg(row.pageNumber);
            } else {
                return section + 1;
            }
        }
    }
    
    return QVariant();
}

bool SpecificationPCBTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid() || index.row() >= m_rows.size() || index.column() >= COLUMN_COUNT) {
        return false;
    }
    
    if (role == Qt::EditRole) {
        SpecificationPCBRowData &rowData = m_rows[index.row()];
        
        // Проверяем, можно ли редактировать эту строку
        if (!canEditRow(index.row())) {
            return false;
        }
        
        QString stringValue = value.toString();
        
        switch (index.column()) {
        case 0: 
            rowData.format.value = stringValue;
            rowData.format.isAutoGenerated = false;
            rowData.format.isEmpty = stringValue.isEmpty();
            break;
        case 1: 
            rowData.zone.value = stringValue;
            rowData.zone.isAutoGenerated = false;
            rowData.zone.isEmpty = stringValue.isEmpty();
            break;
        case 2: 
            rowData.position.value = stringValue;
            rowData.position.isAutoGenerated = false;
            rowData.position.isEmpty = stringValue.isEmpty();
            break;
        case 3: 
            rowData.designation.value = stringValue;
            rowData.designation.isAutoGenerated = false;
            rowData.designation.isEmpty = stringValue.isEmpty();
            break;
        case 4: 
            rowData.name.value = stringValue;
            rowData.name.isAutoGenerated = false;
            rowData.name.isEmpty = stringValue.isEmpty();
            break;
        case 5: 
            rowData.quantity.value = stringValue;
            rowData.quantity.isAutoGenerated = false;
            rowData.quantity.isEmpty = stringValue.isEmpty();
            break;
        case 6: 
            rowData.note.value = stringValue;
            rowData.note.isAutoGenerated = false;
            rowData.note.isEmpty = stringValue.isEmpty();
            break;
        default: return false;
        }
        
        // Обновляем статус пустой строки
        updateRowEmptyStatus(index.row());
        
        emit dataChanged(index, index);
        emit modelDataChanged();
        return true;
    }
    
    return false;
}

bool SpecificationPCBTableModel::setCellStretch(int row, int column, int stretch)
{
    if (row < 0 || row >= m_rows.size() || column < 0 || column >= COLUMN_COUNT) {
        return false;
    }
    
    SpecificationPCBRowData &rowData = m_rows[row];
    bool changed = false;
    
    switch (column) {
    case 0:
        if (rowData.format.stretch != stretch) {
            rowData.format.stretch = stretch;
            changed = true;
        }
        break;
    case 1:
        if (rowData.zone.stretch != stretch) {
            rowData.zone.stretch = stretch;
            changed = true;
        }
        break;
    case 2:
        if (rowData.position.stretch != stretch) {
            rowData.position.stretch = stretch;
            changed = true;
        }
        break;
    case 3:
        if (rowData.designation.stretch != stretch) {
            rowData.designation.stretch = stretch;
            changed = true;
        }
        break;
    case 4:
        if (rowData.name.stretch != stretch) {
            rowData.name.stretch = stretch;
            changed = true;
        }
        break;
    case 5:
        if (rowData.quantity.stretch != stretch) {
            rowData.quantity.stretch = stretch;
            changed = true;
        }
        break;
    case 6:
        if (rowData.note.stretch != stretch) {
            rowData.note.stretch = stretch;
            changed = true;
        }
        break;
    default:
        return false;
    }
    
    if (changed) {
        QModelIndex index = createIndex(row, column);
        emit dataChanged(index, index, QVector<int>() << Qt::UserRole);
        return true;
    }
    
    return false;
}

bool SpecificationPCBTableModel::setCellHeader(int row, int column, bool isHeader)
{
    if (row < 0 || row >= m_rows.size() || column < 0 || column >= COLUMN_COUNT) {
        return false;
    }
    
    SpecificationPCBRowData &rowData = m_rows[row];
    bool changed = false;
    
    switch (column) {
    case 0:
        if (rowData.format.isHeader != isHeader) {
            rowData.format.isHeader = isHeader;
            changed = true;
        }
        break;
    case 1:
        if (rowData.zone.isHeader != isHeader) {
            rowData.zone.isHeader = isHeader;
            changed = true;
        }
        break;
    case 2:
        if (rowData.position.isHeader != isHeader) {
            rowData.position.isHeader = isHeader;
            changed = true;
        }
        break;
    case 3:
        if (rowData.designation.isHeader != isHeader) {
            rowData.designation.isHeader = isHeader;
            changed = true;
        }
        break;
    case 4:
        if (rowData.name.isHeader != isHeader) {
            rowData.name.isHeader = isHeader;
            changed = true;
        }
        break;
    case 5:
        if (rowData.quantity.isHeader != isHeader) {
            rowData.quantity.isHeader = isHeader;
            changed = true;
        }
        break;
    case 6:
        if (rowData.note.isHeader != isHeader) {
            rowData.note.isHeader = isHeader;
            changed = true;
        }
        break;
    default:
        return false;
    }
    
    if (changed) {
        QModelIndex index = createIndex(row, column);
        emit dataChanged(index, index, QVector<int>() << Qt::UserRole);
        return true;
    }
    
    return false;
}

bool SpecificationPCBTableModel::setCellUnderline(int row, int column, bool isUnderline)
{
    if (row < 0 || row >= m_rows.size() || column < 0 || column >= COLUMN_COUNT) {
        return false;
    }
    
    SpecificationPCBRowData &rowData = m_rows[row];
    bool changed = false;
    
    switch (column) {
    case 0:
        if (rowData.format.isUnderline != isUnderline) {
            rowData.format.isUnderline = isUnderline;
            changed = true;
        }
        break;
    case 1:
        if (rowData.zone.isUnderline != isUnderline) {
            rowData.zone.isUnderline = isUnderline;
            changed = true;
        }
        break;
    case 2:
        if (rowData.position.isUnderline != isUnderline) {
            rowData.position.isUnderline = isUnderline;
            changed = true;
        }
        break;
    case 3:
        if (rowData.designation.isUnderline != isUnderline) {
            rowData.designation.isUnderline = isUnderline;
            changed = true;
        }
        break;
    case 4:
        if (rowData.name.isUnderline != isUnderline) {
            rowData.name.isUnderline = isUnderline;
            changed = true;
        }
        break;
    case 5:
        if (rowData.quantity.isUnderline != isUnderline) {
            rowData.quantity.isUnderline = isUnderline;
            changed = true;
        }
        break;
    case 6:
        if (rowData.note.isUnderline != isUnderline) {
            rowData.note.isUnderline = isUnderline;
            changed = true;
        }
        break;
    default:
        return false;
    }
    
    if (changed) {
        QModelIndex index = createIndex(row, column);
        emit dataChanged(index, index, QVector<int>() << Qt::UserRole);
        return true;
    }
    
    return false;
}

bool SpecificationPCBTableModel::isCellOverflow(int row, int column, qreal columnWidth, int fontSize) const
{
    if (row < 0 || row >= m_rows.size() || column < 0 || column >= COLUMN_COUNT) {
        return false;
    }
    
    const SpecificationPCBRowData &rowData = m_rows[row];
    QString cellText;
    int cellStretch = 100;
    
    // Получаем текст и поджим ячейки
    switch (column) {
    case 0: cellText = rowData.format.value; cellStretch = rowData.format.stretch; break;
    case 1: cellText = rowData.zone.value; cellStretch = rowData.zone.stretch; break;
    case 2: cellText = rowData.position.value; cellStretch = rowData.position.stretch; break;
    case 3: cellText = rowData.designation.value; cellStretch = rowData.designation.stretch; break;
    case 4: cellText = rowData.name.value; cellStretch = rowData.name.stretch; break;
    case 5: cellText = rowData.quantity.value; cellStretch = rowData.quantity.stretch; break;
    case 6: cellText = rowData.note.value; cellStretch = rowData.note.stretch; break;
    default: return false;
    }
    
    if (cellText.isEmpty()) {
        return false;
    }
    
    // Используем ту же логику, что и в PDF: масштабирование вместо setStretch
    // Создаем шрифт без поджима для измерения ширины
    QFont testFont("Arial", fontSize); // Используем Arial как приближение
    QFontMetrics metrics(testFont);
    
    // Вычисляем коэффициент масштабирования (как в drawCellWithStretch)
    qreal scaleX = cellStretch / 100.0;
    
    // Вычисляем ширину текста после масштабирования
    qreal textWidth = metrics.horizontalAdvance(cellText) * scaleX;
    
    // Используем ту же логику, что и в PDF: если текст обрезается с многоточием, это переполнение
    // Вычисляем максимальную ширину текста до масштабирования (как в drawCellWithStretch)
    qreal maxTextWidth = columnWidth / scaleX;
    
    // Проверяем, будет ли текст обрезан с многоточием (как в PDF)
    // Если исходный текст шире, чем максимальная ширина, то он будет обрезан
    qreal originalTextWidth = metrics.horizontalAdvance(cellText);
    
    // Добавляем небольшой запас для учета возможных расхождений между Arial и GOST шрифтами
    qreal tolerance = 3.0;
    
    // Переполнение, если текст будет обрезан с многоточием
    return originalTextWidth > (maxTextWidth + tolerance);
}

void SpecificationPCBTableModel::setCellOverflow(int row, int column, bool overflow)
{
    if (row < 0 || row >= m_rows.size() || column < 0 || column >= COLUMN_COUNT) {
        return;
    }
    
    QPair<int, int> cellKey(row, column);
    
    if (overflow) {
        if (!m_overflowCells.contains(cellKey)) {
            m_overflowCells.insert(cellKey);
            QModelIndex index = createIndex(row, column);
            emit dataChanged(index, index, QVector<int>() << Qt::BackgroundRole);
        }
    } else {
        if (m_overflowCells.contains(cellKey)) {
            m_overflowCells.remove(cellKey);
            QModelIndex index = createIndex(row, column);
            emit dataChanged(index, index, QVector<int>() << Qt::BackgroundRole);
        }
    }
}

void SpecificationPCBTableModel::clearOverflowMarks()
{
    if (m_overflowCells.isEmpty()) {
        return;
    }
    
    // Сохраняем индексы для обновления
    QList<QModelIndex> indicesToUpdate;
    QSet<QPair<int, int>>::const_iterator it;
    for (it = m_overflowCells.constBegin(); it != m_overflowCells.constEnd(); ++it) {
        const QPair<int, int> &cellKey = *it;
        indicesToUpdate.append(createIndex(cellKey.first, cellKey.second));
    }
    
    m_overflowCells.clear();
    
    // Обновляем все затронутые ячейки
    for (const QModelIndex &index : indicesToUpdate) {
        emit dataChanged(index, index, QVector<int>() << Qt::BackgroundRole);
    }
}

Qt::ItemFlags SpecificationPCBTableModel::flags(const QModelIndex &index) const
{
    if (!index.isValid()) {
        return Qt::NoItemFlags;
    }
    
    Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    
    // Проверяем, можно ли редактировать эту строку
    if (canEditRow(index.row())) {
        flags |= Qt::ItemIsEditable;
    }
    
    return flags;
}

void SpecificationPCBTableModel::setColumnMappings(const QStringList &mappings)
{
    if (m_columnMappings != mappings) {
        m_columnMappings = mappings;
        emit columnMappingsChanged();
        emit modelDataChanged();
    }
}

QStringList SpecificationPCBTableModel::columnMappings() const
{
    return m_columnMappings;
}

void SpecificationPCBTableModel::addRow(const SpecificationPCBRowData &rowData)
{
    beginInsertRows(QModelIndex(), m_rows.size(), m_rows.size());
    m_rows.append(rowData);
    endInsertRows();
    
    // Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
    // updateRowNumbers();
    
    // Оптимизируем разрывы страниц после добавления строки
    // if (rowData.isHeader) {
    //     optimizePageBreaks();
    // }
    
    emit modelDataChanged();
}

void SpecificationPCBTableModel::insertRow(int position, const SpecificationPCBRowData &rowData)
{
    if (position < 0 || position > m_rows.size()) {
        return;
    }
    
    beginInsertRows(QModelIndex(), position, position);
    m_rows.insert(position, rowData);
    endInsertRows();
    
    // Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
    // updateRowNumbers();
    
    // Оптимизируем разрывы страниц после вставки строки
    // if (rowData.isHeader) {
    //     optimizePageBreaks();
    // }
    
    emit modelDataChanged();
}

void SpecificationPCBTableModel::removeRow(int row)
{
    if (row < 0 || row >= m_rows.size()) {
        return;
    }
    
    // Проверяем, можно ли удалить эту строку
    if (!canEditRow(row)) {
        return;
    }
    
    beginRemoveRows(QModelIndex(), row, row);
    m_rows.removeAt(row);
    endRemoveRows();
    
    // Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
    // updateRowNumbers();
    
    // Оптимизируем разрывы страниц после удаления строки
    // optimizePageBreaks();
    
    emit modelDataChanged();
}

void SpecificationPCBTableModel::clear()
{
    if (m_rows.isEmpty()) {
        return;
    }
    
    beginResetModel();
    m_rows.clear();
    endResetModel();
    
    emit modelDataChanged();
}

void SpecificationPCBTableModel::addEmptyRow()
{
    addRow(createEmptyRow());
}

void SpecificationPCBTableModel::addEmptyRowAt(int position)
{
    insertRow(position, createEmptyRow());
}

SpecificationPCBRowData SpecificationPCBTableModel::createEmptyRow() const
{
    SpecificationPCBRowData row;
    row.isHeader = false;
    row.isEmpty = false; // Строка не пустая, так как может быть отредактирована
    row.rowNumber = 0; // Будет обновлено в updateRowNumbers()
    row.pageNumber = 1;
    
    // Создаем пустые ячейки, но они могут быть отредактированы
    row.format = SpecificationPCBCellData("", 0, 1, false, false, true);
    row.zone = SpecificationPCBCellData("", 0, 1, false, false, true);
    row.position = SpecificationPCBCellData("", 0, 1, false, false, true);
    row.designation = SpecificationPCBCellData("", 0, 1, false, false, true);
    row.name = SpecificationPCBCellData("", 0, 1, false, false, true);
    row.quantity = SpecificationPCBCellData("", 0, 1, false, false, true);
    row.note = SpecificationPCBCellData("", 0, 1, false, false, true);
    
    return row;
}

bool SpecificationPCBTableModel::canEditRow(int row) const
{
    if (row < 0 || row >= m_rows.size()) {
        return false;
    }
    
    // Разрешаем редактирование и удаление всех строк, включая заголовки и автоматически сгенерированные
    return true;
}

void SpecificationPCBTableModel::setComponents(const QList<ComponentModel*> &components)
{
    m_components = components;
    
    // Собираем доступные свойства из компонентов
    m_propertyNames.clear();
    m_propertyNames << "Designator" << "Name" << "Type" << "Value" << "Footprint" << "Description";
    
    for (ComponentModel *component : components) {
        QMap<QString, QString> props = component->properties();
        for (auto it = props.begin(); it != props.end(); ++it) {
            if (!m_propertyNames.contains(it.key())) {
                m_propertyNames.append(it.key());
            }
        }
    }
    
    emit modelDataChanged();
}

void SpecificationPCBTableModel::setPropertyNames(const QStringList &propertyNames)
{
    m_propertyNames = propertyNames;
}

QStringList SpecificationPCBTableModel::availableProperties() const
{
    QStringList properties = m_propertyNames;
    properties.prepend("<Пусто>");
    properties.prepend("<Авто>");
    return properties;
}

QByteArray SpecificationPCBTableModel::saveToDatabase() const
{
    qDebug() << "SpecificationPCBTableModel::saveToDatabase: Начинаем сохранение в БД";
    qDebug() << "SpecificationPCBTableModel::saveToDatabase: Количество строк:" << m_rows.size();
    qDebug() << "SpecificationPCBTableModel::saveToDatabase: Настройки колонок:" << m_columnMappings;
    
    QJsonObject root;
    QJsonArray rowsArray;
    
    for (const SpecificationPCBRowData &row : m_rows) {
        QJsonObject rowObj;
        
        // Сохраняем данные ячеек
        QJsonObject formatObj;
        formatObj["value"] = row.format.value;
        formatObj["rowNumber"] = row.format.rowNumber;
        formatObj["pageNumber"] = row.format.pageNumber;
        formatObj["isHeader"] = row.format.isHeader;
        formatObj["isAutoGenerated"] = row.format.isAutoGenerated;
        formatObj["isEmpty"] = row.format.isEmpty;
        formatObj["stretch"] = row.format.stretch;
        formatObj["isUnderline"] = row.format.isUnderline;
        rowObj["format"] = formatObj;
        
        QJsonObject zoneObj;
        zoneObj["value"] = row.zone.value;
        zoneObj["rowNumber"] = row.zone.rowNumber;
        zoneObj["pageNumber"] = row.zone.pageNumber;
        zoneObj["isHeader"] = row.zone.isHeader;
        zoneObj["isAutoGenerated"] = row.zone.isAutoGenerated;
        zoneObj["isEmpty"] = row.zone.isEmpty;
        zoneObj["stretch"] = row.zone.stretch;
        zoneObj["isUnderline"] = row.zone.isUnderline;
        rowObj["zone"] = zoneObj;
        
        QJsonObject positionObj;
        positionObj["value"] = row.position.value;
        positionObj["rowNumber"] = row.position.rowNumber;
        positionObj["pageNumber"] = row.position.pageNumber;
        positionObj["isHeader"] = row.position.isHeader;
        positionObj["isAutoGenerated"] = row.position.isAutoGenerated;
        positionObj["isEmpty"] = row.position.isEmpty;
        positionObj["stretch"] = row.position.stretch;
        positionObj["isUnderline"] = row.position.isUnderline;
        rowObj["position"] = positionObj;
        
        QJsonObject designationObj;
        designationObj["value"] = row.designation.value;
        designationObj["rowNumber"] = row.designation.rowNumber;
        designationObj["pageNumber"] = row.designation.pageNumber;
        designationObj["isHeader"] = row.designation.isHeader;
        designationObj["isAutoGenerated"] = row.designation.isAutoGenerated;
        designationObj["isEmpty"] = row.designation.isEmpty;
        designationObj["stretch"] = row.designation.stretch;
        designationObj["isUnderline"] = row.designation.isUnderline;
        rowObj["designation"] = designationObj;
        
        QJsonObject nameObj;
        nameObj["value"] = row.name.value;
        nameObj["rowNumber"] = row.name.rowNumber;
        nameObj["pageNumber"] = row.name.pageNumber;
        nameObj["isHeader"] = row.name.isHeader;
        nameObj["isAutoGenerated"] = row.name.isAutoGenerated;
        nameObj["isEmpty"] = row.name.isEmpty;
        nameObj["stretch"] = row.name.stretch;
        nameObj["isUnderline"] = row.name.isUnderline;
        rowObj["name"] = nameObj;
        
        QJsonObject quantityObj;
        quantityObj["value"] = row.quantity.value;
        quantityObj["rowNumber"] = row.quantity.rowNumber;
        quantityObj["pageNumber"] = row.quantity.pageNumber;
        quantityObj["isHeader"] = row.quantity.isHeader;
        quantityObj["isAutoGenerated"] = row.quantity.isAutoGenerated;
        quantityObj["isEmpty"] = row.quantity.isEmpty;
        quantityObj["stretch"] = row.quantity.stretch;
        quantityObj["isUnderline"] = row.quantity.isUnderline;
        rowObj["quantity"] = quantityObj;
        
        QJsonObject noteObj;
        noteObj["value"] = row.note.value;
        noteObj["rowNumber"] = row.note.rowNumber;
        noteObj["pageNumber"] = row.note.pageNumber;
        noteObj["isHeader"] = row.note.isHeader;
        noteObj["isAutoGenerated"] = row.note.isAutoGenerated;
        noteObj["isEmpty"] = row.note.isEmpty;
        noteObj["stretch"] = row.note.stretch;
        noteObj["isUnderline"] = row.note.isUnderline;
        rowObj["note"] = noteObj;
        
        rowObj["isHeader"] = row.isHeader;
        rowObj["isEmpty"] = row.isEmpty;
        rowObj["rowNumber"] = row.rowNumber;
        rowObj["pageNumber"] = row.pageNumber;
        
        rowsArray.append(rowObj);
    }
    
    root["rows"] = rowsArray;
    root["columnMappings"] = QJsonArray::fromStringList(m_columnMappings);
    root["propertyNames"] = QJsonArray::fromStringList(m_propertyNames);
    
    QJsonDocument doc(root);
    QByteArray result = doc.toJson();
    
    qDebug() << "SpecificationPCBTableModel::saveToDatabase: Сохранение завершено, размер данных:" << result.size() << "байт";
    return result;
}

void SpecificationPCBTableModel::loadFromDatabase(const QByteArray &data)
{
    qDebug() << "SpecificationPCBTableModel::loadFromDatabase: Начинаем загрузку из БД, размер данных:" << data.size();
    
    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (!doc.isObject()) {
        qDebug() << "SpecificationPCBTableModel::loadFromDatabase: Ошибка парсинга JSON";
        return;
    }
    
    qDebug() << "SpecificationPCBTableModel::loadFromDatabase: JSON успешно распарсен";

    QJsonObject root = doc.object();
    
    // Загружаем маппинг колонок
    if (root.contains("columnMappings")) {
        QJsonArray mappingsArray = root["columnMappings"].toArray();
        QStringList mappings;
        for (const QJsonValue &value : mappingsArray) {
            mappings.append(value.toString());
        }
        m_columnMappings = mappings;
    }
    
    // Загружаем свойства
    if (root.contains("propertyNames")) {
        QJsonArray propertiesArray = root["propertyNames"].toArray();
        QStringList properties;
        for (const QJsonValue &value : propertiesArray) {
            properties.append(value.toString());
        }
        m_propertyNames = properties;
    }
    
    // Загружаем строки
    clear();
    if (root.contains("rows")) {
        QJsonArray rowsArray = root["rows"].toArray();
        for (const QJsonValue &value : rowsArray) {
            QJsonObject rowObj = value.toObject();
            SpecificationPCBRowData row;
            
            // Загружаем данные ячеек
            if (rowObj.contains("format")) {
                QJsonObject formatObj = rowObj["format"].toObject();
                int stretch = formatObj.contains("stretch") ? formatObj["stretch"].toInt(100) : 100;
                bool isUnderline = formatObj.contains("isUnderline") ? formatObj["isUnderline"].toBool(false) : false;
                row.format = SpecificationPCBCellData(
                    formatObj["value"].toString(),
                    formatObj["rowNumber"].toInt(),
                    formatObj["pageNumber"].toInt(),
                    formatObj["isHeader"].toBool(),
                    formatObj["isAutoGenerated"].toBool(),
                    formatObj["isEmpty"].toBool(),
                    stretch,
                    isUnderline
                );
            }
            
            if (rowObj.contains("zone")) {
                QJsonObject zoneObj = rowObj["zone"].toObject();
                int stretch = zoneObj.contains("stretch") ? zoneObj["stretch"].toInt(100) : 100;
                bool isUnderline = zoneObj.contains("isUnderline") ? zoneObj["isUnderline"].toBool(false) : false;
                row.zone = SpecificationPCBCellData(
                    zoneObj["value"].toString(),
                    zoneObj["rowNumber"].toInt(),
                    zoneObj["pageNumber"].toInt(),
                    zoneObj["isHeader"].toBool(),
                    zoneObj["isAutoGenerated"].toBool(),
                    zoneObj["isEmpty"].toBool(),
                    stretch,
                    isUnderline
                );
            }
            
            if (rowObj.contains("position")) {
                QJsonObject positionObj = rowObj["position"].toObject();
                int stretch = positionObj.contains("stretch") ? positionObj["stretch"].toInt(100) : 100;
                bool isUnderline = positionObj.contains("isUnderline") ? positionObj["isUnderline"].toBool(false) : false;
                row.position = SpecificationPCBCellData(
                    positionObj["value"].toString(),
                    positionObj["rowNumber"].toInt(),
                    positionObj["pageNumber"].toInt(),
                    positionObj["isHeader"].toBool(),
                    positionObj["isAutoGenerated"].toBool(),
                    positionObj["isEmpty"].toBool(),
                    stretch,
                    isUnderline
                );
            }
            
            if (rowObj.contains("designation")) {
                QJsonObject designationObj = rowObj["designation"].toObject();
                int stretch = designationObj.contains("stretch") ? designationObj["stretch"].toInt(100) : 100;
                bool isUnderline = designationObj.contains("isUnderline") ? designationObj["isUnderline"].toBool(false) : false;
                row.designation = SpecificationPCBCellData(
                    designationObj["value"].toString(),
                    designationObj["rowNumber"].toInt(),
                    designationObj["pageNumber"].toInt(),
                    designationObj["isHeader"].toBool(),
                    designationObj["isAutoGenerated"].toBool(),
                    designationObj["isEmpty"].toBool(),
                    stretch,
                    isUnderline
                );
            }
            
            if (rowObj.contains("name")) {
                QJsonObject nameObj = rowObj["name"].toObject();
                int stretch = nameObj.contains("stretch") ? nameObj["stretch"].toInt(100) : 100;
                bool isUnderline = nameObj.contains("isUnderline") ? nameObj["isUnderline"].toBool(false) : false;
                row.name = SpecificationPCBCellData(
                    nameObj["value"].toString(),
                    nameObj["rowNumber"].toInt(),
                    nameObj["pageNumber"].toInt(),
                    nameObj["isHeader"].toBool(),
                    nameObj["isAutoGenerated"].toBool(),
                    nameObj["isEmpty"].toBool(),
                    stretch,
                    isUnderline
                );
            }
            
            if (rowObj.contains("quantity")) {
                QJsonObject quantityObj = rowObj["quantity"].toObject();
                int stretch = quantityObj.contains("stretch") ? quantityObj["stretch"].toInt(100) : 100;
                bool isUnderline = quantityObj.contains("isUnderline") ? quantityObj["isUnderline"].toBool(false) : false;
                row.quantity = SpecificationPCBCellData(
                    quantityObj["value"].toString(),
                    quantityObj["rowNumber"].toInt(),
                    quantityObj["pageNumber"].toInt(),
                    quantityObj["isHeader"].toBool(),
                    quantityObj["isAutoGenerated"].toBool(),
                    quantityObj["isEmpty"].toBool(),
                    stretch,
                    isUnderline
                );
            }
            
            if (rowObj.contains("note")) {
                QJsonObject noteObj = rowObj["note"].toObject();
                int stretch = noteObj.contains("stretch") ? noteObj["stretch"].toInt(100) : 100;
                bool isUnderline = noteObj.contains("isUnderline") ? noteObj["isUnderline"].toBool(false) : false;
                row.note = SpecificationPCBCellData(
                    noteObj["value"].toString(),
                    noteObj["rowNumber"].toInt(),
                    noteObj["pageNumber"].toInt(),
                    noteObj["isHeader"].toBool(),
                    noteObj["isAutoGenerated"].toBool(),
                    noteObj["isEmpty"].toBool(),
                    stretch,
                    isUnderline
                );
            }
            
            row.isHeader = rowObj["isHeader"].toBool();
            row.isEmpty = rowObj["isEmpty"].toBool();
            row.rowNumber = rowObj["rowNumber"].toInt();
            row.pageNumber = rowObj["pageNumber"].toInt();
            
            addRow(row);
        }
    }
    
    qDebug() << "SpecificationPCBTableModel::loadFromDatabase: Загружено строк:" << m_rows.size();
    qDebug() << "SpecificationPCBTableModel::loadFromDatabase: Маппинг колонок:" << m_columnMappings;
    qDebug() << "SpecificationPCBTableModel::loadFromDatabase: Свойства:" << m_propertyNames;
    
    emit columnMappingsChanged();
}

QString SpecificationPCBTableModel::getDocumentTitle() const
{
    return "Спецификация печатной платы";
}

QString SpecificationPCBTableModel::getDocumentType() const
{
    return "SpecificationPCB";
}

QList<SpecificationPCBRowData> SpecificationPCBTableModel::getRows() const
{
    return m_rows;
}

bool SpecificationPCBTableModel::isRowHeader(int row) const
{
    if (row < 0 || row >= m_rows.size()) {
        return false;
    }
    return m_rows[row].isHeader;
}

void SpecificationPCBTableModel::updatePageNumbers()
{
    qDebug() << "SpecificationPCBTableModel::updatePageNumbers: Обновляем номера страниц";
    
    int currentRow = 0;
    int currentPage = 1;
    int rowsOnCurrentPage = 0;
    bool pageNumbersChanged = false;
    
    for (int i = 0; i < m_rows.size(); ++i) {
        SpecificationPCBRowData &row = m_rows[i];
        
        // Сохраняем старый номер страницы для проверки изменений
        int oldPageNumber = row.pageNumber;
        
        // Определяем, сколько строк помещается на текущей странице
        int maxRowsOnPage = (currentPage == 1) ? ROWS_PER_FIRST_PAGE : ROWS_PER_OTHER_PAGE;
        
        // Если текущая страница заполнена, переходим на следующую
        if (rowsOnCurrentPage >= maxRowsOnPage) {
            currentPage++;
            rowsOnCurrentPage = 0;
            maxRowsOnPage = ROWS_PER_OTHER_PAGE; // Начиная со второй страницы
        }
        
        // Проверяем, изменился ли номер страницы
        if (oldPageNumber != currentPage) {
            pageNumbersChanged = true;
        }
        
        // Устанавливаем номер страницы для строки
        row.pageNumber = currentPage;
        row.format.pageNumber = currentPage;
        row.zone.pageNumber = currentPage;
        row.position.pageNumber = currentPage;
        row.designation.pageNumber = currentPage;
        row.name.pageNumber = currentPage;
        row.quantity.pageNumber = currentPage;
        row.note.pageNumber = currentPage;
        
        // Увеличиваем счетчик строк на текущей странице
        rowsOnCurrentPage++;
        currentRow++;
        
        qDebug() << "SpecificationPCBTableModel::updatePageNumbers: Строка" << i << "на странице" << currentPage 
                 << "(строк на странице:" << rowsOnCurrentPage << "/" << maxRowsOnPage << ")";
    }
    
    qDebug() << "SpecificationPCBTableModel::updatePageNumbers: Обновление завершено, всего страниц:" << currentPage;
    
    // Уведомляем UI об изменении данных ТОЛЬКО если номера страниц действительно изменились
    // Это критично для производительности при редактировании больших таблиц
    if (pageNumbersChanged && !m_rows.isEmpty()) {
        emit dataChanged(index(0, 0), index(m_rows.size() - 1, COLUMN_COUNT - 1), 
                        QVector<int>() << Qt::BackgroundRole);
        emit headerDataChanged(Qt::Vertical, 0, m_rows.size() - 1);
    }
}

int SpecificationPCBTableModel::getPageForRow(int rowNumber) const
{
    if (rowNumber <= 0) return 1;
    
    int currentRow = 0;
    int currentPage = 1;
    
    for (int i = 0; i < m_rows.size(); ++i) {
        int maxRowsOnPage = (currentPage == 1) ? ROWS_PER_FIRST_PAGE : ROWS_PER_OTHER_PAGE;
        
        if (currentRow + 1 > maxRowsOnPage) {
            currentPage++;
            currentRow = 0;
            maxRowsOnPage = ROWS_PER_OTHER_PAGE;
        }
        
        currentRow++;
        
        if (i + 1 == rowNumber) {
            return currentPage;
        }
    }
    
    return currentPage;
}

bool SpecificationPCBTableModel::needsPageBreakProtection(int rowIndex) const
{
    if (rowIndex < 0 || rowIndex >= m_rows.size()) {
        return false;
    }
    
    const SpecificationPCBRowData &row = m_rows[rowIndex];
    
    // Проверяем только заголовки групп
    if (!row.isHeader) {
        return false;
    }
    
    // Получаем номер страницы для текущей строки
    int currentPage = row.pageNumber;
    
    // Определяем максимальное количество строк на текущей странице
    int maxRowsOnPage = (currentPage == 1) ? ROWS_PER_FIRST_PAGE : ROWS_PER_OTHER_PAGE;
    
    // Подсчитываем количество строк на текущей странице до этой строки
    int rowsOnCurrentPage = 0;
    for (int i = 0; i < rowIndex; ++i) {
        if (m_rows[i].pageNumber == currentPage) {
            rowsOnCurrentPage++;
        }
    }
    
    // Проверяем, находится ли заголовок на последней или предпоследней строке страницы
    // Заголовки обособлены пустыми строками с двух сторон, поэтому:
    // - Если заголовок на последней строке страницы - нужна защита
    // - Если заголовок на предпоследней строке страницы - нужна защита (чтобы пустая строка после заголовка не оказалась на следующей странице)
    if (rowsOnCurrentPage == maxRowsOnPage - 1 || rowsOnCurrentPage == maxRowsOnPage - 2) {
        // Проверяем, есть ли элементы группы на следующей странице
        for (int i = rowIndex + 1; i < m_rows.size(); ++i) {
            // Если встретили другой заголовок, значит это уже другая группа
            if (m_rows[i].isHeader) {
                break;
            }
            
            // Если элемент группы находится на следующей странице
            if (m_rows[i].pageNumber == currentPage + 1 && !m_rows[i].isEmpty) {
                qDebug() << "SpecificationPCBTableModel::needsPageBreakProtection: Заголовок на строке" << rowIndex 
                         << "нуждается в защите от разрыва страницы (элемент группы на странице" << (currentPage + 1) 
                         << ", заголовок на строке" << (rowsOnCurrentPage + 1) << "из" << maxRowsOnPage << ")";
                return true;
            }
        }
    }
    
    return false;
}

void SpecificationPCBTableModel::addPageBreakProtection()
{
    qDebug() << "SpecificationPCBTableModel::addPageBreakProtection: Добавляем защиту от разрывов страниц";
    
    // Сначала обновляем номера страниц
    updatePageNumbers();
    
    // Собираем информацию о заголовках, которые нуждаются в защите
    QList<PageBreakInfo> pageBreakInfos;
    
    for (int i = 0; i < m_rows.size(); ++i) {
        if (needsPageBreakProtection(i)) {
            const SpecificationPCBRowData &row = m_rows[i];
            int currentPage = row.pageNumber;
            int maxRowsOnPage = (currentPage == 1) ? ROWS_PER_FIRST_PAGE : ROWS_PER_OTHER_PAGE;
            
            // Подсчитываем количество строк на текущей странице до этой строки
            int rowsOnCurrentPage = 0;
            for (int j = 0; j < i; ++j) {
                if (m_rows[j].pageNumber == currentPage) {
                    rowsOnCurrentPage++;
                }
            }
            
            // Определяем, сколько пустых строк нужно добавить
            int emptyRowsToAdd = 1; // По умолчанию одна строка
            
            if (rowsOnCurrentPage == maxRowsOnPage - 2) {
                // Заголовок на предпоследней строке - добавляем две пустые строки
                emptyRowsToAdd = 2;
                qDebug() << "SpecificationPCBTableModel::addPageBreakProtection: Заголовок на предпоследней строке, добавляем" << emptyRowsToAdd << "пустые строки перед строкой" << i;
            } else {
                qDebug() << "SpecificationPCBTableModel::addPageBreakProtection: Заголовок на последней строке, добавляем" << emptyRowsToAdd << "пустую строку перед строкой" << i;
            }
            
            // Создаем информацию о переносе
            PageBreakInfo info;
            info.rowIndex = i;
            info.headerText = row.name.value;
            info.currentPage = currentPage;
            info.nextPage = currentPage + 1;
            info.emptyRowsToAdd = emptyRowsToAdd;
            
            pageBreakInfos.append(info);
        }
    }
    
    // Если есть заголовки для защиты, запрашиваем подтверждение
    if (!pageBreakInfos.isEmpty()) {
        qDebug() << "SpecificationPCBTableModel::addPageBreakProtection: Найдено" << pageBreakInfos.size() << "заголовков для защиты";
        
        // Находим главное окно приложения
        QWidget *mainWindow = nullptr;
        for (QWidget *widget : QApplication::topLevelWidgets()) {
            if (widget->isVisible() && widget->windowTitle().contains("GostGenerator", Qt::CaseInsensitive)) {
                mainWindow = widget;
                break;
            }
        }
        
        // Создаем и показываем диалог подтверждения
        PageBreakConfirmationDialog dialog(pageBreakInfos, mainWindow);
        if (dialog.exec() == QDialog::Accepted) {
            // Получаем подтвержденные строки
            QList<int> confirmedRows = dialog.getConfirmedRows();
            
            // Добавляем пустые строки только для подтвержденных заголовков
            for (int i = 0; i < m_rows.size(); ++i) {
                if (needsPageBreakProtection(i) && confirmedRows.contains(i)) {
                    const SpecificationPCBRowData &row = m_rows[i];
                    int currentPage = row.pageNumber;
                    int maxRowsOnPage = (currentPage == 1) ? ROWS_PER_FIRST_PAGE : ROWS_PER_OTHER_PAGE;
                    
                    // Подсчитываем количество строк на текущей странице до этой строки
                    int rowsOnCurrentPage = 0;
                    for (int j = 0; j < i; ++j) {
                        if (m_rows[j].pageNumber == currentPage) {
                            rowsOnCurrentPage++;
                        }
                    }
                    
                    // Определяем, сколько пустых строк нужно добавить
                    int emptyRowsToAdd = 1; // По умолчанию одна строка
                    
                    if (rowsOnCurrentPage == maxRowsOnPage - 2) {
                        // Заголовок на предпоследней строке - добавляем две пустые строки
                        emptyRowsToAdd = 2;
                        qDebug() << "SpecificationPCBTableModel::addPageBreakProtection: Добавляем" << emptyRowsToAdd << "пустые строки перед строкой" << i;
                    } else {
                        qDebug() << "SpecificationPCBTableModel::addPageBreakProtection: Добавляем" << emptyRowsToAdd << "пустую строку перед строкой" << i;
                    }
                    
                    // Добавляем нужное количество пустых строк перед заголовком
                    for (int k = 0; k < emptyRowsToAdd; ++k) {
                        SpecificationPCBRowData emptyRow = createEmptyRow();
                        insertRow(i, emptyRow);
                    }
                    
                    // Обновляем номера страниц после вставки
                    updatePageNumbers();
                    
                    // Пропускаем вставленные строки
                    i += emptyRowsToAdd;
                }
            }
        } else {
            qDebug() << "SpecificationPCBTableModel::addPageBreakProtection: Пользователь отменил добавление защиты от разрывов страниц";
        }
    }
    
    // Обновляем отображение страниц в UI
    updatePageDisplay();
    
    qDebug() << "SpecificationPCBTableModel::addPageBreakProtection: Защита от разрывов страниц добавлена";
}

void SpecificationPCBTableModel::optimizePageBreaks()
{
    updatePageNumbers();
    addPageBreakProtection();
}

void SpecificationPCBTableModel::updatePageDisplay()
{
    qDebug() << "SpecificationPCBTableModel::updatePageDisplay: Обновляем отображение страниц в UI";
    
    // Сохраняем старые номера страниц для проверки изменений
    QList<int> oldPageNumbers;
    for (const SpecificationPCBRowData &row : m_rows) {
        oldPageNumbers.append(row.pageNumber);
    }
    
    // Обновляем номера страниц
    updatePageNumbers();
    
    // Проверяем, изменились ли номера страниц
    bool pageNumbersChanged = false;
    for (int i = 0; i < m_rows.size() && i < oldPageNumbers.size(); ++i) {
        if (m_rows[i].pageNumber != oldPageNumbers[i]) {
            pageNumbersChanged = true;
            break;
        }
    }
    
    // Уведомляем UI об изменении данных ТОЛЬКО если номера страниц действительно изменились
    // Это критично для производительности при редактировании больших таблиц
    if (pageNumbersChanged && !m_rows.isEmpty()) {
        emit dataChanged(index(0, 0), index(m_rows.size() - 1, COLUMN_COUNT - 1), 
                        QVector<int>() << Qt::BackgroundRole);
        
        // Обновляем вертикальные заголовки
        emit headerDataChanged(Qt::Vertical, 0, m_rows.size() - 1);
    }
    
    qDebug() << "SpecificationPCBTableModel::updatePageDisplay: Отображение страниц обновлено";
}

void SpecificationPCBTableModel::updateRowNumbers()
{
    int rowNumber = 1;
    for (SpecificationPCBRowData &row : m_rows) {
        if (!row.isHeader) {
            row.rowNumber = rowNumber++;
        }
    }
}

void SpecificationPCBTableModel::updateRowEmptyStatus(int row)
{
    if (row < 0 || row >= m_rows.size()) {
        return;
    }
    
    SpecificationPCBRowData &rowData = m_rows[row];
    
    // Проверяем, пустые ли все ячейки
    bool allEmpty = rowData.format.value.isEmpty() &&
                   rowData.zone.value.isEmpty() &&
                   rowData.position.value.isEmpty() &&
                   rowData.designation.value.isEmpty() &&
                   rowData.name.value.isEmpty() &&
                   rowData.quantity.value.isEmpty() &&
                   rowData.note.value.isEmpty();
    
    // Обновляем флаг isEmpty для строки
    if (rowData.isEmpty != allEmpty) {
        rowData.isEmpty = allEmpty;
        qDebug() << "SpecificationPCBTableModel::updateRowEmptyStatus: Строка" << row << "обновлена, isEmpty =" << allEmpty;
    }
}

SpecificationPCBCellData SpecificationPCBTableModel::createCellData(const QString &value, bool isHeader, bool isAuto, bool isEmpty)
{
    return SpecificationPCBCellData(value, 0, 1, isHeader, isAuto, isEmpty);
} 
