#include "specificationcontroller.h"
#include "../model/specificationtablemodel.h"
#include "../model/designatormappingmodel.h"
#include "../model/projectsettingsmodel.h"
#include "../model/projectparamtablemodel.h"
#include "../model/pcbmaterialmodel.h"
#include "../controller/maincontroller.h"
#include <QDebug>
#include <QCollator>

SpecificationController::SpecificationController(QObject *parent)
    : QObject(parent)
    , m_tableModel(new SpecificationTableModel(this))
    , m_designatorMappingModel(nullptr)
    , m_projectSettingsModel(nullptr)
    , m_mainController(nullptr)
    , m_pcbMaterialModel(nullptr)
{
    // Устанавливаем маппинг по умолчанию для спецификации
    m_columnMappings << "Format" << "Zone" << "Position" << "Designation" << "Name" << "Quantity" << "Note";
}

SpecificationController::~SpecificationController()
{
    // m_tableModel удалится автоматически, так как он является дочерним объектом
}

void SpecificationController::setDesignatorMappingModel(DesignatorMappingModel *mappingModel)
{
    m_designatorMappingModel = mappingModel;
}

void SpecificationController::setModel(SpecificationTableModel *model)
{
    if (m_tableModel != model) {
        qDebug() << "SpecificationController::setModel: Заменяем модель таблицы";
        m_tableModel = model;
        
        // Если модель не пуста, загружаем из неё настройки колонок
        if (m_tableModel) {
            QStringList columnMappings = m_tableModel->columnMappings();
            if (!columnMappings.isEmpty()) {
                qDebug() << "SpecificationController::setModel: Загружаем настройки колонок из модели:" << columnMappings;
                m_columnMappings = columnMappings;
            }
        }
    }
}

void SpecificationController::setProjectSettingsModel(ProjectSettingsModel *model)
{
    m_projectSettingsModel = model;
    qDebug() << "SpecificationController::setProjectSettingsModel: Установлена модель настроек проекта";
}

void SpecificationController::setMainController(MainController *controller)
{
    m_mainController = controller;
    qDebug() << "SpecificationController::setMainController: Установлен главный контроллер";
}

void SpecificationController::setMaterials(const QList<PCBMaterialModel*> &materials)
{
    qDebug() << "SpecificationController::setMaterials: Устанавливаем" << materials.size() << "материалов";
    m_materials = materials;

    // Собираем доступные свойства из материалов
    m_propertyNames = collectPropertyNames();
    qDebug() << "SpecificationController::setMaterials: Собрано свойств:" << m_propertyNames.size();
    qDebug() << "SpecificationController::setMaterials: Свойства:" << m_propertyNames;
}

void SpecificationController::setPCBMaterialModel(PCBMaterialModel* model)
{
    qDebug() << "SpecificationController::setPCBMaterialModel: Устанавливаем PCB модель материалов";
    m_pcbMaterialModel = model;
    
    if (m_pcbMaterialModel) {
        qDebug() << "SpecificationController::setPCBMaterialModel: Материалов в модели:" << m_pcbMaterialModel->getMaterialCount();
    }
}

void SpecificationController::generateTableFromMaterials()
{
    if (!m_tableModel) {
        return;
    }

    qDebug() << "SpecificationController::generateTableFromMaterials: Начинаем генерацию таблицы";
    qDebug() << "SpecificationController::generateTableFromMaterials: Текущие настройки колонок:" << m_columnMappings;

    // Очищаем таблицу
    m_tableModel->clear();
    
    // Добавляем заголовок таблицы
    SpecificationRowData emptyRow;
    emptyRow.isEmpty = true;
    m_tableModel->addRow(emptyRow);
    
    SpecificationRowData headerRow;
    headerRow.isHeader = true;
    headerRow.format = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow.zone = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow.position = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow.designation = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow.name = SpecificationCellData("Документаця", 0, 1, true, false, false, 100, true);
    headerRow.quantity = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow.note = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    m_tableModel->addRow(headerRow);

    m_tableModel->addRow(emptyRow);

    SpecificationRowData defaultRow1;
    defaultRow1.isHeader = false;
    defaultRow1.format = SpecificationCellData("A1", 0, 1, false, false, false, 100, false);
    defaultRow1.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
    defaultRow1.position = SpecificationCellData("", 0, 1, false, false, false, 100, false);
    defaultRow1.designation = SpecificationCellData(getDecimalNumberBoard() + "Э3 СБ", 0, 1, false, false, false, 100, false);
    defaultRow1.name = SpecificationCellData("Сборочный чертеж", 0, 1, false, false, false, 100, false);
    defaultRow1.quantity = SpecificationCellData("", 0, 1, false, false, false, 100, false);
    defaultRow1.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
    m_tableModel->addRow(defaultRow1);

    SpecificationRowData defaultRow2;

    defaultRow2.isHeader = false;
    defaultRow2.format = SpecificationCellData("*)", 0, 1, false, false, false, 100, false);
    defaultRow2.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
    defaultRow2.position = SpecificationCellData("", 0, 1, false, false, false, 100, false);
    defaultRow2.designation = SpecificationCellData(getDecimalNumberBoard() + " Э3 Т5М", 0, 1, false, false, false, 100, false);
    defaultRow2.name = SpecificationCellData("Данные проектирования", 0, 1, false, false, false, 100, false);
    defaultRow2.quantity = SpecificationCellData("", 0, 1, false, false, false, 100, false);
    defaultRow2.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
    m_tableModel->addRow(defaultRow2);  


    m_tableModel->addRow(emptyRow);

    SpecificationRowData headerRow2;
    headerRow2.isHeader = true;
    headerRow2.format = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow2.zone = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow2.position = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow2.designation = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow2.name = SpecificationCellData("Материалы", 0, 1, true, false, false, 100, true);
    headerRow2.quantity = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    headerRow2.note = SpecificationCellData("", 0, 1, true, false, false, 100, true);
    m_tableModel->addRow(headerRow2);

    m_tableModel->addRow(emptyRow);


    if (!m_pcbMaterialModel || m_pcbMaterialModel->getMaterialCount() == 0) {
        qDebug() << "SpecificationController::generateTableFromMaterials: Нет материалов для генерации";
        return;
    }

    qDebug() << "SpecificationController::generateTableFromMaterials: Материалов для обработки:" << m_pcbMaterialModel->getMaterialCount();

    try {
        // Получаем список материалов из PCB модели
        QList<PCBMaterialData> materials = m_pcbMaterialModel->getMaterials();
        
        // Сортируем материалы по номеру слоя
        std::sort(materials.begin(), materials.end(),
                  [](const PCBMaterialData &a, const PCBMaterialData &b) {
                      return a.layerNumber < b.layerNumber;
                  });

        // Группируем материалы по названию и типу
        QMap<QString, QList<PCBMaterialData>> groupedByName;
        for (const PCBMaterialData &material : materials) {
            QString materialName = material.name;
            groupedByName[materialName].append(material);
        }

        // Подсчитываем количество ядер (dielType = 1 в модели PCB)
        int coreCount = 0;
        for (const PCBMaterialData &material : materials) {
            if (material.dielType == 1) {
                coreCount++;
            }
        }
        
        // Подсчитываем общее количество слоев
        int totalLayers = m_pcbMaterialModel->getLayerCount();
        
        // Рассчитываем количество фольги: (общее количество слоев - количество ядер)
        int foilCount = totalLayers - coreCount*2;
        
        // Обрабатываем каждую группу материалов
        int pos = 1;
        for (auto it = groupedByName.begin(); it != groupedByName.end(); ++it) {
            QString materialName = it.key();
            QList<PCBMaterialData> materialsInGroup = it.value();
            
            // Определяем тип материала и формируем название
            QString displayName;
            int quantity = 0;
            
            if (materialName == "DielMaterial") {
                // Для диэлектрических материалов группируем по значению
                QMap<QString, QList<PCBMaterialData>> groupedByValue;
                for (const PCBMaterialData &material : materialsInGroup) {
                    QString value = material.value;
                    groupedByValue[value].append(material);
                }
                
                // Обрабатываем каждое значение диэлектрика
                for (auto valueIt = groupedByValue.begin(); valueIt != groupedByValue.end(); ++valueIt) {
                    QString value = valueIt.key();
                    QList<PCBMaterialData> valueMaterials = valueIt.value();
                    
                    // Определяем тип диэлектрика и формируем название
                    QString dielTypeName;
                    if (value == "FR4 PR") {
                        dielTypeName = "Препрег FR4 PR";
                    } else if (value == "FR4 Tg150") {
                        dielTypeName = "Стеклотекстолит FR4 Tg150";
                    } else if (value == "Solder Resist") {
                        dielTypeName = "Паяльная маска";
                    } else {
                        dielTypeName = value;
                    }
                    
                    // Добавляем толщину к названию
                    if (!valueMaterials.isEmpty()) {
                        double thickness = valueMaterials.first().height;
                        displayName = QString("%1 %2 мм").arg(dielTypeName).arg(QString::number(thickness, 'f', 3));
                    }
                    
                    quantity = valueMaterials.size();
                    
                    // Добавляем строку в таблицу
                    SpecificationRowData row;
                    row.format = SpecificationCellData("", 0, 1, false, false, false, 100, false);
                    row.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
                    row.position = SpecificationCellData(QString::number(pos++), 0, 1, false, false, false, 100, false);
                    row.designation = SpecificationCellData("", 0, 1, false, false, false, 100, false);
                    row.name = SpecificationCellData(displayName, 0, 1, false, false, false, 100, false);
                    row.quantity = SpecificationCellData(QString::number(quantity), 0, 1, false, false, false, 100, false);
                    row.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
                    
                    m_tableModel->addRow(row);
                }
            } else {
                // Для других материалов (например, фольга)
                displayName = materialName;
                quantity = materialsInGroup.size();
                
                // Добавляем строку в таблицу
                SpecificationRowData row;
                row.format = SpecificationCellData("", 0, 1, false, false, false, 100, false);
                row.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
                row.position = SpecificationCellData(QString::number(pos++), 0, 1, false, false, false, 100, false);
                row.designation = SpecificationCellData("", 0, 1, false, false, false, 100, false);
                row.name = SpecificationCellData(displayName, 0, 1, false, false, false, 100, false);
                row.quantity = SpecificationCellData(QString::number(quantity), 0, 1, false, false, false, 100, false);
                row.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
                
                m_tableModel->addRow(row);
            }
        }
        
        // Добавляем фольгу в конец, если она есть
        if (foilCount > 0) {
            SpecificationRowData foilRow;
            foilRow.format = SpecificationCellData("", 0, 1, false, false, false, 100, false);
            foilRow.zone = SpecificationCellData("", 0, 1, false, false, false, 100, false);
            foilRow.position = SpecificationCellData(QString::number(pos++), 0, 1, false, false, false, 100, false);
            foilRow.designation = SpecificationCellData("", 0, 1, false, false, false, 100, false);
            foilRow.name = SpecificationCellData("Фольга медная толщиной 18 мкм", 0, 1, false, false, false, 100, false);
            foilRow.quantity = SpecificationCellData(QString::number(foilCount), 0, 1, false, false, false, 100, false);
            foilRow.note = SpecificationCellData("", 0, 1, false, false, false, 100, false);
            
            m_tableModel->addRow(foilRow);
        }

        qDebug() << "SpecificationController::generateTableFromMaterials: Таблица сгенерирована, строк:" << m_tableModel->rowCount();
        
        // Оптимизируем разрывы страниц после генерации таблицы
        m_tableModel->optimizePageBreaks();
        
    } catch (const std::exception &e) {
        qDebug() << "SpecificationController::generateTableFromMaterials: Ошибка при генерации:" << e.what();
    } catch (...) {
        qDebug() << "SpecificationController::generateTableFromMaterials: Неизвестная ошибка при генерации";
    }
}

void SpecificationController::updateTableFromMaterials()
{
    if (!m_tableModel) {
        qDebug() << "SpecificationController::updateTableFromMaterials: m_tableModel is null";
        return;
    }

    qDebug() << "SpecificationController::updateTableFromMaterials: Обновляем таблицу из" << m_materials.size() << "материалов";

    if (m_materials.isEmpty()) {
        qDebug() << "SpecificationController::updateTableFromMaterials: Нет материалов для обновления";
        return;
    }

    try {
        // Метод updateTableFromMaterials больше не используется в новой логике
        qDebug() << "SpecificationController::updateTableFromMaterials: Метод устарел";
    } catch (const std::exception &e) {
        qDebug() << "SpecificationController::updateTableFromMaterials: Ошибка при обновлении:" << e.what();
    } catch (...) {
        qDebug() << "SpecificationController::updateTableFromMaterials: Неизвестная ошибка при обновлении";
    }
}

QString SpecificationController::getMaterialValue(PCBMaterialModel *material, const QString &propertyName)
{
    if (!material) {
        return "";
    }

    qDebug() << "SpecificationController::getMaterialValue: propertyName =" << propertyName;

    // Получаем значение свойства материала
    QString value;
    if (propertyName == "Name") {
        value = material->getMaterialName(0); // Получаем название первого материала
        qDebug() << "SpecificationController::getMaterialValue: Name =" << value;
    } else if (propertyName == "Value") {
        value = material->getMaterialValue(0);
        qDebug() << "SpecificationController::getMaterialValue: Value =" << value;
    } else if (propertyName == "Height") {
        value = material->formatHeight(material->getMaterialHeight(0));
        qDebug() << "SpecificationController::getMaterialValue: Height =" << value;
    } else if (propertyName == "DielType") {
        value = material->formatDielType(material->getMaterialDielType(0));
        qDebug() << "SpecificationController::getMaterialValue: DielType =" << value;
    } else if (propertyName == "LayerNumber") {
        value = QString::number(material->getMaterialLayerNumber(0));
        qDebug() << "SpecificationController::getMaterialValue: LayerNumber =" << value;
    } else {
        qDebug() << "SpecificationController::getMaterialValue: Неизвестное свойство" << propertyName;
        return "";
    }

    // Проверяем, является ли значение свойства выражением
    if (value.startsWith("=")) {
        qDebug() << "SpecificationController::getMaterialValue: Значение свойства является выражением:" << value;
        return parseExpression(material, value);
    }

    return value;
}

QString SpecificationController::formatDielType(int dielType)
{
    switch (dielType) {
        case 0: return "Ядро";
        case 1: return "Препрег";
        default: return "Неизвестно";
    }
}

QString SpecificationController::parseExpression(PCBMaterialModel *material, const QString &expression)
{
    if (!material) {
        return "";
    }

    qDebug() << "SpecificationController::parseExpression: Обрабатываем выражение:" << expression;

    QString result;
    QString expr;

    // Определяем, как обрабатывать выражение
    if (expression.startsWith("=")) {
        expr = expression.mid(1); // Убираем начальный "="
    } else if (expression.startsWith("\"") && expression.endsWith("\"")) {
        // Если это просто значение в кавычках, возвращаем его без кавычек
        return expression.mid(1, expression.length() - 2);
    } else {
        // Если это не выражение, возвращаем как есть
        return expression;
    }

    // Разбиваем выражение по операторам "+" с учетом кавычек
    QStringList parts;
    QString currentPart;
    bool inDoubleQuotes = false;
    bool inSingleQuotes = false;

    for (int i = 0; i < expr.length(); ++i) {
        QChar ch = expr[i];

        if (ch == '"' && !inSingleQuotes) {
            inDoubleQuotes = !inDoubleQuotes;
            currentPart += ch;
        } else if (ch == '\'' && !inDoubleQuotes) {
            inSingleQuotes = !inSingleQuotes;
            currentPart += ch;
        } else if (ch == '+' && !inDoubleQuotes && !inSingleQuotes) {
            // Это разделитель "+" вне кавычек
            if (!currentPart.trimmed().isEmpty()) {
                parts.append(currentPart.trimmed());
            }
            currentPart.clear();
        } else {
            currentPart += ch;
        }
    }

    // Добавляем последнюю часть
    if (!currentPart.trimmed().isEmpty()) {
        parts.append(currentPart.trimmed());
    }

    qDebug() << "SpecificationController::parseExpression: Части выражения:" << parts;

    for (const QString &part : parts) {
        QString trimmedPart = part.trimmed();
        qDebug() << "SpecificationController::parseExpression: Обрабатываем часть:" << trimmedPart;

        // Если это не пустая строка, добавляем к результату
        if (!trimmedPart.isEmpty()) {
            QString value;

            // Проверяем, является ли это литералом в одинарных кавычках
            if (trimmedPart.startsWith("'") && trimmedPart.endsWith("'")) {
                // Это литерал - убираем кавычки и используем как есть
                value = trimmedPart.mid(1, trimmedPart.length() - 2);
                qDebug() << "SpecificationController::parseExpression: Найден литерал в одинарных кавычках:" << value;
            }
            // Проверяем, является ли это именем свойства материала в двойных кавычках
            else if (trimmedPart.startsWith("\"") && trimmedPart.endsWith("\"")) {
                // Это свойство материала - убираем кавычки и ищем в свойствах
                QString propertyName = trimmedPart.mid(1, trimmedPart.length() - 2);
                qDebug() << "SpecificationController::parseExpression: Ищем свойство материала:" << propertyName;

                value = getMaterialValue(material, propertyName);
                qDebug() << "SpecificationController::parseExpression: Найдено свойство" << propertyName << "=" << value;
                // Рекурсивно обрабатываем вложенные выражения (getMaterialValue уже обрабатывает первый уровень)
                // Но если значение само является выражением, нужно обработать его еще раз
                if (value.startsWith("=")) {
                    qDebug() << "SpecificationController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
                    value = parseExpression(material, value);
                }
            }
            // Проверяем, является ли это именем свойства материала без кавычек
            else {
                // Ищем в свойствах материала
                value = getMaterialValue(material, trimmedPart);
                qDebug() << "SpecificationController::parseExpression: Ищем свойство" << trimmedPart << "в материале, результат:" << value;
                // Рекурсивно обрабатываем вложенные выражения (getMaterialValue уже обрабатывает первый уровень)
                // Но если значение само является выражением, нужно обработать его еще раз
                if (value.startsWith("=")) {
                    qDebug() << "SpecificationController::parseExpression: Значение свойства является вложенным выражением, рекурсивно обрабатываем";
                    value = parseExpression(material, value);
                }
            }

            // Добавляем значение к результату
            if (!value.isEmpty()) {
                if (!result.isEmpty()) {
                    result += value;
                } else {
                    result = value;
                }
                qDebug() << "SpecificationController::parseExpression: Добавили к результату, текущий результат:" << result;
            }
        }
    }

    qDebug() << "SpecificationController::parseExpression: Финальный результат:" << result;
    return result;
}

QStringList SpecificationController::collectPropertyNames()
{
    QStringList propertyNames;

    // Добавляем основные свойства материала
    propertyNames << "Name" << "Value" << "Height" << "DielType" << "LayerNumber";

    // Если дополнительные свойства не найдены в материалах, добавляем стандартные
    if (propertyNames.size() <= 5) { // Только базовые свойства
        propertyNames << "Format" << "Zone" << "Position" << "Designation" << "Quantity" << "Note";
        qDebug() << "SpecificationController: Дополнительные свойства не найдены, используем стандартные:" << propertyNames;
    }

    // Добавляем специальное свойство для количества материалов в группе
    propertyNames << "Quantity" << "Кол.";

    return propertyNames;
}

// Методы для работы с децимальными номерами
QString SpecificationController::getDecimalNumberBoard() const
{
    QStringList mappings = getColumnMappings();
    if (mappings.size() > 7) {
        QString fieldName = mappings[7];
        if (!fieldName.isEmpty()) {
            // Получаем значение из projectparamtable
            if (m_mainController) {
                ProjectParamTableModel *paramModel = m_mainController->projectParamTableModel();
                if (paramModel) {
                    QMap<QString, QString> params = paramModel->getDataAsMap();
                    if (params.contains(fieldName)) {
                        return params[fieldName]; // Возвращаем значение, а не название поля
                    }
                }
            }
            // Если не удалось получить значение из модели, возвращаем название поля
            return fieldName;
        }
    }
    return QString();
}

void SpecificationController::setDecimalNumberBoard(const QString &value)
{
    QStringList mappings = getColumnMappings();
    while (mappings.size() <= 7) {
        mappings.append("");
    }
    mappings[7] = value;
    setColumnMappings(mappings);
}

QString SpecificationController::getDecimalNumberDocument() const
{
    QStringList mappings = getColumnMappings();
    if (mappings.size() > 8) {
        QString fieldName = mappings[8];
        if (!fieldName.isEmpty()) {
            // Получаем значение из projectparamtable
            if (m_mainController) {
                ProjectParamTableModel *paramModel = m_mainController->projectParamTableModel();
                if (paramModel) {
                    QMap<QString, QString> params = paramModel->getDataAsMap();
                    if (params.contains(fieldName)) {
                        return params[fieldName]; // Возвращаем значение, а не название поля
                    }
                }
            }
            // Если не удалось получить значение из модели, возвращаем название поля
            return fieldName;
        }
    }
    return QString();
}

void SpecificationController::setDecimalNumberDocument(const QString &value)
{
    QStringList mappings = getColumnMappings();
    while (mappings.size() <= 8) {
        mappings.append("");
    }
    mappings[8] = value;
    setColumnMappings(mappings);
}

void SpecificationController::setColumnMappings(const QStringList &mappings)
{
    qDebug() << "SpecificationController::setColumnMappings: Устанавливаем новые настройки колонок:" << mappings;
    m_columnMappings = mappings;
    
    // Сохраняем настройки в ProjectSettingsModel
    if (m_projectSettingsModel) {
        for (int i = 0; i < mappings.size(); ++i) {
            m_projectSettingsModel->setColumnMapping("Specification", i, mappings[i]);
        }
        qDebug() << "SpecificationController::setColumnMappings: Настройки сохранены в ProjectSettingsModel";
    }
    
    // Обновляем настройки в модели
    if (m_tableModel) {
        m_tableModel->setColumnMappings(mappings);
        qDebug() << "SpecificationController::setColumnMappings: Настройки обновлены в модели";
    }
    
    qDebug() << "SpecificationController::setColumnMappings: Настройки колонок обновлены:" << m_columnMappings;
}

QStringList SpecificationController::getColumnMappings() const
{
    // Если есть ProjectSettingsModel, читаем настройки из него
    if (m_projectSettingsModel) {
        QStringList settings = m_projectSettingsModel->getColumnMappings("Specification");
        if (!settings.isEmpty()) {
            qDebug() << "SpecificationController::getColumnMappings: Получены настройки из ProjectSettingsModel:" << settings;
            return settings;
        }
    }
    
    // Fallback: возвращаем локальные настройки
    qDebug() << "SpecificationController::getColumnMappings: Возвращаем локальные настройки:" << m_columnMappings;
    return m_columnMappings;
}

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

QString SpecificationController::getMaterialType(PCBMaterialModel *material)
{
    if (!material) return "";

    // Получаем тип материала из свойств
    QString type = material->formatDielType(material->getMaterialDielType(0));
    if (!type.isEmpty()) {
        return type;
    }

    // Если тип не найден, используем fallback
    return "Материал";
}

QPair<QString, QString> SpecificationController::splitDesignator(const QString &designator)
{
    if (designator.isEmpty()) {
        return QPair<QString, QString>("", "");
    }

    // Используем регулярное выражение для разделения буквенной и цифровой части
    QRegExp regex("([A-Za-z]+)(\\d*)");
    if (regex.indexIn(designator) != -1) {
        QString letterPart = regex.cap(1);
        QString numberPart = regex.cap(2);
        return QPair<QString, QString>(letterPart, numberPart);
    }

    // Fallback: если регулярное выражение не сработало,
    // ищем первую цифру и разделяем по ней
    for (int i = 0; i < designator.length(); ++i) {
        if (designator[i].isDigit()) {
            QString letterPart = designator.left(i);
            QString numberPart = designator.mid(i);
            return QPair<QString, QString>(letterPart, numberPart);
        }
    }

    // Если цифр нет, возвращаем весь десигнатор как буквенную часть
    return QPair<QString, QString>(designator, "");
}

// Новые методы для управления строками
void SpecificationController::addEmptyRow()
{
    if (m_tableModel) {
        m_tableModel->addEmptyRow();
        qDebug() << "SpecificationController::addEmptyRow: Добавлена пустая строка";
        
        // Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
        // m_tableModel->optimizePageBreaks();
    }
}

void SpecificationController::addEmptyRowAt(int position)
{
    if (m_tableModel) {
        m_tableModel->addEmptyRowAt(position);
        qDebug() << "SpecificationController::addEmptyRowAt: Добавлена пустая строка в позицию" << position;
        
        // Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
        // m_tableModel->optimizePageBreaks();
    }
}

void SpecificationController::insertEmptyRowAt(int position)
{
    if (m_tableModel) {
        m_tableModel->addEmptyRowAt(position);
        qDebug() << "SpecificationController::insertEmptyRowAt: Вставлена пустая строка в позицию" << position;
        
        // Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
        // m_tableModel->optimizePageBreaks();
    }
}

void SpecificationController::removeRow(int row)
{
    if (m_tableModel) {
        m_tableModel->removeRow(row);
        qDebug() << "SpecificationController::removeRow: Удалена строка" << row;
        
        // Автоматический пересчет отключен - пересчет выполняется по кнопке "Пересчет таблицы"
        // m_tableModel->optimizePageBreaks();
    }
}

void SpecificationController::clearTable()
{
    if (m_tableModel) {
        m_tableModel->clear();
        qDebug() << "SpecificationController::clearTable: Таблица очищена";
    }
}

void SpecificationController::optimizePageBreaks()
{
    if (m_tableModel) {
        qDebug() << "SpecificationController::optimizePageBreaks: Оптимизируем разрывы страниц";
        m_tableModel->optimizePageBreaks();
    }
}

int SpecificationController::getFontSize() const
{
    if (m_projectSettingsModel) {
        return m_projectSettingsModel->getFontSize("Specification");
    }
    return 12; // По умолчанию
}

void SpecificationController::setFontSize(int fontSize)
{
    if (m_projectSettingsModel) {
        m_projectSettingsModel->setFontSize("Specification", fontSize);
    }
}

int SpecificationController::getFontStretch() const
{
    if (m_projectSettingsModel) {
        return m_projectSettingsModel->getFontStretch("Specification");
    }
    return 100; // По умолчанию (нормальный)
}

void SpecificationController::setFontStretch(int stretch)
{
    if (m_projectSettingsModel) {
        m_projectSettingsModel->setFontStretch("Specification", stretch);
    }
}

QList<QString> SpecificationController::splitLongDesignation(const QString &designation, const QString originalString, PCBMaterialModel *material, int maxLength)
{
    QList<QString> result;
    
    if (designation.length() <= maxLength) {
        result.append(designation);
        return result;
    }
    
    qDebug() << "SpecificationController::splitLongDesignation: Разделяем длинное наименование:" << designation;
    
    // Обычный текст - разделяем по пробелам
    result = splitBySpaces(designation, maxLength);
    
    qDebug() << "SpecificationController::splitLongDesignation: Результат разделения:" << result;
    return result;
}

QList<QString> SpecificationController::splitBySpaces(const QString &text, int maxLength)
{
    QList<QString> result;
    
    if (text.length() <= maxLength) {
        result.append(text);
        return result;
    }
    
    // Ищем пробел, ближайший к середине строки
    int targetLength = maxLength;
    int bestSplitPos = -1;
    int minDifference = text.length(); // Минимальная разница с целевой длиной
    
    // Ищем пробелы в тексте
    for (int i = 0; i < text.length(); ++i) {
        if (text[i] == ' ') {
            int leftLength = i;
            int rightLength = text.length() - i - 1;
            
            // Вычисляем разницу с целевой длиной
            int leftDiff = abs(leftLength - targetLength);
            int rightDiff = abs(rightLength - targetLength);
            int totalDiff = leftDiff + rightDiff;
            
            // Если эта позиция лучше предыдущей, запоминаем её
            if (totalDiff < minDifference) {
                minDifference = totalDiff;
                bestSplitPos = i;
            }
        }
    }
    
    // Если нашли подходящий пробел, разделяем по нему
    if (bestSplitPos != -1) {
        QString leftPart = text.left(bestSplitPos).trimmed();
        QString rightPart = text.mid(bestSplitPos + 1).trimmed();
        
        // Рекурсивно обрабатываем обе части
        if (!leftPart.isEmpty()) {
            QList<QString> leftParts = splitBySpaces(leftPart, maxLength);
            result.append(leftParts);
        }
        
        if (!rightPart.isEmpty()) {
            QList<QString> rightParts = splitBySpaces(rightPart, maxLength);
            result.append(rightParts);
        }
    } else {
        // Если пробелов нет или не удалось найти подходящий, разбиваем посимвольно
        // for (int i = 0; i < text.length(); i += maxLength) {
        //     result.append(text.mid(i, maxLength));
        // }
        result.append(text);
    }
    
    return result;
}

QString SpecificationController::getMaterialFormat(PCBMaterialModel *material)
{
    if (!material) return "";
    
    // Получаем формат из свойств материала
    // Для материалов платы обычно используется стандартный формат
    return "A4";
}

QString SpecificationController::getMaterialZone(PCBMaterialModel *material)
{
    if (!material) return "";
    
    // Получаем зону из свойств материала
    // Для материалов платы зона обычно не указывается
    return "";
}

QString SpecificationController::getMaterialPosition(PCBMaterialModel *material)
{
    if (!material) return "";
    
    // Для спецификации материалов позиция обычно совпадает с номером слоя
    return QString::number(material->getMaterialLayerNumber(0));
} 
