#include "databasecontroller.h"
#include <QSqlRecord>
#include <QSqlField>
#include <QThread> // Added for QThread::currentThreadId()

#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QFileInfo> // Added for QFileInfo

// Инициализация статического счетчика
int DataBaseController::s_connectionCounter = 0;

DataBaseController::DataBaseController(QObject *parent)
    : QObject(parent)
{
}

DataBaseController::~DataBaseController()
{
    if (m_database.isOpen()) {
        m_database.close();
    }
}

bool DataBaseController::initializeDatabase(const QString &dbPath, const QString &connectionName)
{
    // Закрываем предыдущее соединение, если оно открыто
    if (m_database.isOpen()) {
        m_database.close();
    }
    
    // Удаляем предыдущее соединение, если оно существует
    if (!connectionName.isEmpty()) {
        QSqlDatabase::removeDatabase(connectionName);
    }
    
    // Создаем новое соединение с уникальным именем
    QString connName = connectionName.isEmpty() ? "default" : connectionName;
    m_database = QSqlDatabase::addDatabase("QSQLITE", connName);
    m_database.setDatabaseName(dbPath);
    
    if (!m_database.open()) {
        setLastError("Не удалось открыть базу данных: " + m_database.lastError().text());
        return false;
    }
    
    return createTables();
}

bool DataBaseController::createTables()
{
    QStringList tables = {
        "CREATE TABLE IF NOT EXISTS variants ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    name TEXT UNIQUE NOT NULL"
        ")",
        
        "CREATE TABLE IF NOT EXISTS components ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    designator TEXT UNIQUE NOT NULL"
        ")",
        
        "CREATE TABLE IF NOT EXISTS component_properties ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    component_id INTEGER NOT NULL,"
        "    property_name TEXT NOT NULL,"
        "    property_value TEXT,"
        "    FOREIGN KEY(component_id) REFERENCES components(id) ON DELETE CASCADE,"
        "    UNIQUE(component_id, property_name)"
        ")",
        
        "CREATE TABLE IF NOT EXISTS component_variants ("
        "    component_id INTEGER NOT NULL,"
        "    variant_id INTEGER NOT NULL,"
        "    is_fitted BOOLEAN DEFAULT 1,"
        "    PRIMARY KEY(component_id, variant_id),"
        "    FOREIGN KEY(component_id) REFERENCES components(id) ON DELETE CASCADE,"
        "    FOREIGN KEY(variant_id) REFERENCES variants(id) ON DELETE CASCADE"
        ")",
        
        "CREATE TABLE IF NOT EXISTS variant_properties ("
        "    component_id INTEGER NOT NULL,"
        "    variant_id INTEGER NOT NULL,"
        "    property_name TEXT NOT NULL,"
        "    property_value TEXT,"
        "    PRIMARY KEY(component_id, variant_id, property_name),"
        "    FOREIGN KEY(component_id) REFERENCES components(id) ON DELETE CASCADE,"
        "    FOREIGN KEY(variant_id) REFERENCES variants(id) ON DELETE CASCADE"
        ")",
        
        "CREATE TABLE IF NOT EXISTS project_params ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    name TEXT UNIQUE NOT NULL,"
        "    value TEXT"
        ")",
        "CREATE TABLE IF NOT EXISTS project_settings ("
        "    key TEXT PRIMARY KEY,"
        "    value TEXT"
        ")",
        
        "CREATE TABLE IF NOT EXISTS designator_mappings ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    designator TEXT UNIQUE NOT NULL,"
        "    singular_name TEXT NOT NULL,"
        "    plural_name TEXT NOT NULL,"
        "    is_custom BOOLEAN DEFAULT 0"
        ")",
        
        "CREATE TABLE IF NOT EXISTS title_inscriptions ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    project_name TEXT NOT NULL,"
        "    field_number INTEGER NOT NULL,"
        "    field_value TEXT,"
        "    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    UNIQUE(project_name, field_number)"
        ")",
        "CREATE TABLE IF NOT EXISTS perechen_rows ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    project_name TEXT NOT NULL,"
        "    row_order INTEGER NOT NULL,"
        "    position_value TEXT,"
        "    designation_value TEXT,"
        "    quantity_value TEXT,"
        "    note_value TEXT,"
        "    is_header BOOLEAN DEFAULT 0,"
        "    is_empty BOOLEAN DEFAULT 0,"
        "    position_is_auto BOOLEAN DEFAULT 0,"
        "    designation_is_auto BOOLEAN DEFAULT 0,"
        "    quantity_is_auto BOOLEAN DEFAULT 0,"
        "    note_is_auto BOOLEAN DEFAULT 0,"
        "    cell_stretches TEXT,"
        "    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP"
        ")",
        "CREATE TABLE IF NOT EXISTS specification_pcb_rows ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    project_name TEXT NOT NULL,"
        "    row_order INTEGER NOT NULL,"
        "    format_value TEXT,"
        "    zone_value TEXT,"
        "    position_value TEXT,"
        "    designation_value TEXT,"
        "    name_value TEXT,"
        "    quantity_value TEXT,"
        "    note_value TEXT,"
        "    is_header BOOLEAN DEFAULT 0,"
        "    is_empty BOOLEAN DEFAULT 0,"
        "    format_is_auto BOOLEAN DEFAULT 0,"
        "    zone_is_auto BOOLEAN DEFAULT 0,"
        "    position_is_auto BOOLEAN DEFAULT 0,"
        "    designation_is_auto BOOLEAN DEFAULT 0,"
        "    name_is_auto BOOLEAN DEFAULT 0,"
        "    quantity_is_auto BOOLEAN DEFAULT 0,"
        "    note_is_auto BOOLEAN DEFAULT 0,"
        "    cell_stretches TEXT,"
        "    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP"
        ")",
        
        "CREATE TABLE IF NOT EXISTS specification_rows ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    project_name TEXT NOT NULL,"
        "    row_order INTEGER NOT NULL,"
        "    format_value TEXT,"
        "    zone_value TEXT,"
        "    position_value TEXT,"
        "    designation_value TEXT,"
        "    name_value TEXT,"
        "    quantity_value TEXT,"
        "    note_value TEXT,"
        "    is_header BOOLEAN DEFAULT 0,"
        "    is_empty BOOLEAN DEFAULT 0,"
        "    format_is_auto BOOLEAN DEFAULT 0,"
        "    zone_is_auto BOOLEAN DEFAULT 0,"
        "    position_is_auto BOOLEAN DEFAULT 0,"
        "    designation_is_auto BOOLEAN DEFAULT 0,"
        "    name_is_auto BOOLEAN DEFAULT 0,"
        "    quantity_is_auto BOOLEAN DEFAULT 0,"
        "    note_is_auto BOOLEAN DEFAULT 0,"
        "    cell_stretches TEXT,"
        "    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP"
        ")",
        
        "CREATE TABLE IF NOT EXISTS vedomost_rows ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    project_name TEXT NOT NULL,"
        "    row_order INTEGER NOT NULL,"
        "    name_value TEXT,"
        "    product_code_value TEXT,"
        "    document_code_value TEXT,"
        "    supplier_value TEXT,"
        "    where_used_value TEXT,"
        "    quantity_per_item_value TEXT,"
        "    quantity_in_set_value TEXT,"
        "    quantity_for_reg_value TEXT,"
        "    total_quantity_value TEXT,"
        "    note_value TEXT,"
        "    is_header BOOLEAN DEFAULT 0,"
        "    is_empty BOOLEAN DEFAULT 0,"
        "    name_is_auto BOOLEAN DEFAULT 0,"
        "    product_code_is_auto BOOLEAN DEFAULT 0,"
        "    document_code_is_auto BOOLEAN DEFAULT 0,"
        "    supplier_is_auto BOOLEAN DEFAULT 0,"
        "    where_used_is_auto BOOLEAN DEFAULT 0,"
        "    quantity_per_item_is_auto BOOLEAN DEFAULT 0,"
        "    quantity_in_set_is_auto BOOLEAN DEFAULT 0,"
        "    quantity_for_reg_is_auto BOOLEAN DEFAULT 0,"
        "    total_quantity_is_auto BOOLEAN DEFAULT 0,"
        "    note_is_auto BOOLEAN DEFAULT 0,"
        "    row_number INTEGER DEFAULT 0,"
        "    page_number INTEGER DEFAULT 1,"
        "    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP"
        ")",
        "CREATE TABLE IF NOT EXISTS simple_list_rows ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    project_name TEXT NOT NULL,"
        "    row_order INTEGER NOT NULL,"
        "    designator_value TEXT,"
        "    name_value TEXT,"
        "    quantity_value TEXT,"
        "    is_empty BOOLEAN DEFAULT 0,"
        "    designator_is_auto BOOLEAN DEFAULT 0,"
        "    name_is_auto BOOLEAN DEFAULT 0,"
        "    quantity_is_auto BOOLEAN DEFAULT 0,"
        "    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP"
        ")",
        
        "CREATE TABLE IF NOT EXISTS pcb_data ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    layer_count INTEGER DEFAULT 0,"
        "    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP"
        ")",
        
        "CREATE TABLE IF NOT EXISTS diel_materials ("
        "    id INTEGER PRIMARY KEY AUTOINCREMENT,"
        "    pcb_id INTEGER NOT NULL,"
        "    name TEXT NOT NULL,"
        "    value TEXT,"
        "    height REAL DEFAULT 0.0,"
        "    diel_type INTEGER DEFAULT 0,"
        "    layer_number INTEGER NOT NULL,"
        "    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,"
        "    FOREIGN KEY(pcb_id) REFERENCES pcb_data(id) ON DELETE CASCADE,"
        "    UNIQUE(pcb_id, layer_number)"
        ")"
    };
    
    for (const QString &tableQuery : tables) {
        if (!executeQuery(tableQuery)) {
            return false;
        }
    }
    
    // Миграция: добавляем поле cell_stretches в существующие таблицы, если его нет
    migrateAddCellStretchesColumn();
    
    return true;
}

void DataBaseController::migrateAddCellStretchesColumn()
{
    qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Проверяем наличие поля cell_stretches";
    
    // Список таблиц, в которые нужно добавить поле cell_stretches
    QStringList tables = {"perechen_rows", "specification_pcb_rows", "specification_rows", "vedomost_rows"};
    
    for (const QString &tableName : tables) {
        // Проверяем, существует ли колонка cell_stretches
        QSqlQuery checkQuery = prepareQuery(
            QString("PRAGMA table_info(%1)").arg(tableName)
        );
        
        bool columnExists = false;
        if (checkQuery.exec()) {
            while (checkQuery.next()) {
                QString columnName = checkQuery.value(1).toString();
                if (columnName == "cell_stretches") {
                    columnExists = true;
                    break;
                }
            }
        }
        
        if (!columnExists) {
            qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Добавляем поле cell_stretches в таблицу" << tableName;
            QSqlQuery alterQuery = prepareQuery(
                QString("ALTER TABLE %1 ADD COLUMN cell_stretches TEXT").arg(tableName)
            );
            if (!alterQuery.exec()) {
                qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Ошибка добавления колонки в" << tableName << ":" << alterQuery.lastError().text();
            } else {
                qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Поле cell_stretches успешно добавлено в" << tableName;
            }
        } else {
            qDebug() << "DataBaseController::migrateAddCellStretchesColumn: Поле cell_stretches уже существует в" << tableName;
        }
    }
}

int DataBaseController::addVariant(const QString &name)
{
    QSqlQuery query = prepareQuery("INSERT INTO variants (name) VALUES (?)");
    query.addBindValue(name);
    
    if (!query.exec()) {
        setLastError("Ошибка добавления варианта: " + query.lastError().text());
        return -1;
    }
    
    return query.lastInsertId().toInt();
}

bool DataBaseController::removeVariant(int variantId)
{
    QSqlQuery query = prepareQuery("DELETE FROM variants WHERE id = ?");
    query.addBindValue(variantId);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления варианта: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QList<VariantData> DataBaseController::getAllVariants()
{
    QList<VariantData> variants;
    QSqlQuery query = prepareQuery("SELECT id, name FROM variants");
    if (query.exec()) {
        while (query.next()) {
            VariantData variant;
            variant.id = query.value(0).toInt();
            variant.name = query.value(1).toString();
            variants << variant;
        }
    }
    return variants;
}

int DataBaseController::getVariantId(const QString &name)
{
    QSqlQuery query = prepareQuery("SELECT id FROM variants WHERE name = ?");
    query.addBindValue(name);
    if (query.exec() && query.next()) {
        return query.value(0).toInt();
    }
    return -1;
}

int DataBaseController::addComponent(const QString &designator)
{
    QSqlQuery query = prepareQuery("INSERT INTO components (designator) VALUES (?)");
    query.addBindValue(designator);
    
    if (!query.exec()) {
        setLastError("Ошибка добавления компонента: " + query.lastError().text());
        return -1;
    }
    
    return query.lastInsertId().toInt();
}

bool DataBaseController::removeComponent(int componentId)
{
    QSqlQuery query = prepareQuery("DELETE FROM components WHERE id = ?");
    query.addBindValue(componentId);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления компонента: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

bool DataBaseController::updateComponentDesignator(int componentId, const QString &designator)
{
    QSqlQuery query = prepareQuery("UPDATE components SET designator = ? WHERE id = ?");
    query.addBindValue(designator);
    query.addBindValue(componentId);
    return query.exec();
}

QList<ComponentData> DataBaseController::getAllComponents()
{
    QList<ComponentData> components;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return components;
    }
    
    QSqlQuery query = prepareQuery("SELECT id, designator FROM components ORDER BY designator");
    
    if (!query.exec()) {
        setLastError("Ошибка получения компонентов: " + query.lastError().text());
        return components;
    }
    
    while (query.next()) {
        ComponentData component;
        component.id = query.value(0).toInt();
        component.designator = query.value(1).toString();
        component.baseProperties = getComponentProperties(component.id);
        

        
        // Получаем варианты для компонента
        QSqlQuery variantQuery = prepareQuery(
            "SELECT v.id, v.name, cv.is_fitted FROM variants v "
            "JOIN component_variants cv ON v.id = cv.variant_id "
            "WHERE cv.component_id = ?"
        );
        variantQuery.addBindValue(component.id);
        
        if (variantQuery.exec()) {
            while (variantQuery.next()) {
                int variantId = variantQuery.value(0).toInt();
                QString variantName = variantQuery.value(1).toString();
                bool fitted = variantQuery.value(2).toBool();
                
                component.variantFitted[variantName] = fitted;
                

                
                // Получаем свойства варианта
                QSqlQuery propQuery = prepareQuery(
                    "SELECT property_name, property_value FROM variant_properties "
                    "WHERE component_id = ? AND variant_id = ?"
                );
                propQuery.addBindValue(component.id);
                propQuery.addBindValue(variantId);
                
                if (propQuery.exec()) {
                    QMap<QString, QString> variantProps;
                    while (propQuery.next()) {
                        QString propName = propQuery.value(0).toString();
                        QString propValue = propQuery.value(1).toString();
                        variantProps[propName] = propValue;
                    }
                    component.variantProperties[variantName] = variantProps;
                    

                } else {

                }
            }
        } else {

        }
        

        components.append(component);
    }
    
    return components;
}

ComponentData DataBaseController::getComponent(int componentId)
{
    ComponentData component;
    QSqlQuery query = prepareQuery("SELECT id, designator FROM components WHERE id = ?");
    query.addBindValue(componentId);
    
    if (!query.exec() || !query.next()) {
        return component;
    }
    
    component.id = query.value(0).toInt();
    component.designator = query.value(1).toString();
    component.baseProperties = getComponentProperties(componentId);
    
    // Получаем варианты для компонента
    QSqlQuery variantQuery = prepareQuery(
        "SELECT v.id, v.name, cv.is_fitted FROM variants v "
        "JOIN component_variants cv ON v.id = cv.variant_id "
        "WHERE cv.component_id = ?"
    );
    variantQuery.addBindValue(componentId);
    
    if (variantQuery.exec()) {
        while (variantQuery.next()) {
            int variantId = variantQuery.value(0).toInt();
            QString variantName = variantQuery.value(1).toString();
            bool fitted = variantQuery.value(2).toBool();
            
            component.variantFitted[variantName] = fitted;
            
            // Получаем свойства варианта
            QSqlQuery propQuery = prepareQuery(
                "SELECT property_name, property_value FROM variant_properties "
                "WHERE component_id = ? AND variant_id = ?"
            );
            propQuery.addBindValue(componentId);
            propQuery.addBindValue(variantId);
            
            if (propQuery.exec()) {
                QMap<QString, QString> variantProps;
                while (propQuery.next()) {
                    QString propName = propQuery.value(0).toString();
                    QString propValue = propQuery.value(1).toString();
                    variantProps[propName] = propValue;
                }
                component.variantProperties[variantName] = variantProps;
            }
        }
    }
    
    return component;
}

ComponentData DataBaseController::getComponent(const QString &designator)
{
    ComponentData component;
    QSqlQuery query = prepareQuery("SELECT id, designator FROM components WHERE designator = ?");
    query.addBindValue(designator);
    
    if (!query.exec() || !query.next()) {
        return component;
    }
    
    component.id = query.value(0).toInt();
    component.designator = query.value(1).toString();
    component.baseProperties = getComponentProperties(component.id);
    
    // Получаем варианты для компонента
    QSqlQuery variantQuery = prepareQuery(
        "SELECT v.id, v.name, cv.is_fitted FROM variants v "
        "JOIN component_variants cv ON v.id = cv.variant_id "
        "WHERE cv.component_id = ?"
    );
    variantQuery.addBindValue(component.id);
    
    if (variantQuery.exec()) {
        while (variantQuery.next()) {
            int variantId = variantQuery.value(0).toInt();
            QString variantName = variantQuery.value(1).toString();
            bool fitted = variantQuery.value(2).toBool();
            
            component.variantFitted[variantName] = fitted;
            
            // Получаем свойства варианта
            QSqlQuery propQuery = prepareQuery(
                "SELECT property_name, property_value FROM variant_properties "
                "WHERE component_id = ? AND variant_id = ?"
            );
            propQuery.addBindValue(component.id);
            propQuery.addBindValue(variantId);
            
            if (propQuery.exec()) {
                QMap<QString, QString> variantProps;
                while (propQuery.next()) {
                    QString propName = propQuery.value(0).toString();
                    QString propValue = propQuery.value(1).toString();
                    variantProps[propName] = propValue;
                }
                component.variantProperties[variantName] = variantProps;
            }
        }
    }
    
    return component;
}

bool DataBaseController::saveComponents(const QList<ComponentData> &components)
{
    // Очищаем существующие компоненты
    if (!executeQuery("DELETE FROM components")) {
        return false;
    }
    
    // Добавляем новые компоненты
    for (const auto& component : components) {
        int componentId = addComponent(component.designator);
        if (componentId == -1) {
            return false;
        }
        
        // Сохраняем свойства
        for (auto it = component.baseProperties.begin(); it != component.baseProperties.end(); ++it) {
            if (!setComponentProperty(componentId, it.key(), it.value())) {
                return false;
            }
        }
        
        // Сохраняем варианты
        for (auto it = component.variantFitted.begin(); it != component.variantFitted.end(); ++it) {
            int variantId = getVariantId(it.key());
            if (variantId != -1) {
                setComponentVariantFitted(componentId, variantId, it.value());
            }
        }
        
        // Сохраняем свойства вариантов
        for (auto it = component.variantProperties.begin(); it != component.variantProperties.end(); ++it) {
            int variantId = getVariantId(it.key());
            if (variantId != -1) {
                for (auto propIt = it.value().begin(); propIt != it.value().end(); ++propIt) {
                    setVariantProperty(componentId, variantId, propIt.key(), propIt.value());
                }
            }
        }
    }
    
    return true;
}

QMap<QString, QString> DataBaseController::getComponentProperties(int componentId)
{
    QMap<QString, QString> properties;
    QSqlQuery query = prepareQuery(
        "SELECT property_name, property_value FROM component_properties WHERE component_id = ?"
    );
    query.addBindValue(componentId);
    
    if (!query.exec()) {
        setLastError("Ошибка получения свойств компонента: " + query.lastError().text());
        return properties;
    }
    
    while (query.next()) {
        QString propertyName = query.value(0).toString();
        QString propertyValue = query.value(1).toString();
        properties[propertyName] = propertyValue;
    }
    
    return properties;
}

bool DataBaseController::setComponentProperty(int componentId, const QString &propertyName, const QString &propertyValue)
{
    QSqlQuery query = prepareQuery("INSERT OR REPLACE INTO component_properties (component_id, property_name, property_value) VALUES (?, ?, ?)");
    query.addBindValue(componentId);
    query.addBindValue(propertyName);
    query.addBindValue(propertyValue);
    return query.exec();
}

bool DataBaseController::removeComponentProperty(int componentId, const QString &propertyName)
{
    QSqlQuery query = prepareQuery("DELETE FROM component_properties WHERE component_id = ? AND property_name = ?");
    query.addBindValue(componentId);
    query.addBindValue(propertyName);
    return query.exec();
}

bool DataBaseController::setComponentVariantFitted(int componentId, int variantId, bool fitted)
{
    QSqlQuery query = prepareQuery("INSERT OR REPLACE INTO component_variants (component_id, variant_id, is_fitted) VALUES (?, ?, ?)");
    query.addBindValue(componentId);
    query.addBindValue(variantId);
    query.addBindValue(fitted);
    return query.exec();
}

bool DataBaseController::setVariantProperty(int componentId, int variantId, const QString &propertyName, const QString &propertyValue)
{
    QSqlQuery query = prepareQuery("INSERT OR REPLACE INTO variant_properties (component_id, variant_id, property_name, property_value) VALUES (?, ?, ?, ?)");
    query.addBindValue(componentId);
    query.addBindValue(variantId);
    query.addBindValue(propertyName);
    query.addBindValue(propertyValue);
    return query.exec();
}

bool DataBaseController::removeVariantProperty(int componentId, int variantId, const QString &propertyName)
{
    QSqlQuery query = prepareQuery(
        "DELETE FROM variant_properties WHERE component_id = ? AND variant_id = ? AND property_name = ?"
    );
    query.addBindValue(componentId);
    query.addBindValue(variantId);
    query.addBindValue(propertyName);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления свойства варианта: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QList<ComponentData> DataBaseController::getComponentsForVariant(int variantId)
{
    QList<ComponentData> components;
    QSqlQuery query = prepareQuery(
        "SELECT c.id, c.designator, cv.is_fitted FROM components c "
        "JOIN component_variants cv ON c.id = cv.component_id "
        "WHERE cv.variant_id = ? "
        "ORDER BY c.designator"
    );
    query.addBindValue(variantId);
    
    if (!query.exec()) {
        setLastError("Ошибка получения компонентов для варианта: " + query.lastError().text());
        return components;
    }
    
    while (query.next()) {
        ComponentData component;
        component.id = query.value(0).toInt();
        component.designator = query.value(1).toString();
        bool fitted = query.value(2).toBool();
        
        // Получаем базовые свойства
        component.baseProperties = getComponentProperties(component.id);
        
        // Получаем ВСЕ варианты для этого компонента
        QSqlQuery allVariantsQuery = prepareQuery(
            "SELECT v.id, v.name, cv.is_fitted FROM variants v "
            "JOIN component_variants cv ON v.id = cv.variant_id "
            "WHERE cv.component_id = ?"
        );
        allVariantsQuery.addBindValue(component.id);
        
        if (allVariantsQuery.exec()) {
            while (allVariantsQuery.next()) {
                int currentVariantId = allVariantsQuery.value(0).toInt();
                QString currentVariantName = allVariantsQuery.value(1).toString();
                bool currentFitted = allVariantsQuery.value(2).toBool();
                
                component.variantFitted[currentVariantName] = currentFitted;
                
                // Получаем свойства для текущего варианта
                QSqlQuery propQuery = prepareQuery(
                    "SELECT property_name, property_value FROM variant_properties "
                    "WHERE component_id = ? AND variant_id = ?"
                );
                propQuery.addBindValue(component.id);
                propQuery.addBindValue(currentVariantId);
                
                if (propQuery.exec()) {
                    QMap<QString, QString> variantProps;
                    while (propQuery.next()) {
                        QString propName = propQuery.value(0).toString();
                        QString propValue = propQuery.value(1).toString();
                        variantProps[propName] = propValue;
                    }
                    component.variantProperties[currentVariantName] = variantProps;
                }
            }
        }
        
        components.append(component);
    }
    
    return components;
}

QList<ComponentData> DataBaseController::getComponentsForVariant(const QString &variantName)
{
    int variantId = getVariantId(variantName);
    if (variantId == -1) {
        setLastError("Вариант не найден: " + variantName);
        return QList<ComponentData>();
    }
    
    return getComponentsForVariant(variantId);
}

QStringList DataBaseController::getAllPropertyNames()
{
    QStringList propertyNames;
    QSqlQuery query = prepareQuery("SELECT DISTINCT property_name FROM component_properties");
    if (query.exec()) {
        while (query.next()) {
            propertyNames << query.value(0).toString();
        }
    }
    return propertyNames;
}

int DataBaseController::addProjectParam(const QString &name, const QString &value)
{
    QSqlQuery query = prepareQuery("INSERT INTO project_params (name, value) VALUES (?, ?)");
    query.addBindValue(name);
    query.addBindValue(value);
    
    if (!query.exec()) {
        setLastError("Ошибка добавления параметра проекта: " + query.lastError().text());
        return -1;
    }
    
    emit dataChanged();
    return query.lastInsertId().toInt();
}

bool DataBaseController::updateProjectParam(int paramId, const QString &name, const QString &value)
{
    QSqlQuery query = prepareQuery("UPDATE project_params SET name = ?, value = ? WHERE id = ?");
    query.addBindValue(name);
    query.addBindValue(value);
    query.addBindValue(paramId);
    
    if (!query.exec()) {
        setLastError("Ошибка обновления параметра проекта: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

bool DataBaseController::removeProjectParam(int paramId)
{
    QSqlQuery query = prepareQuery("DELETE FROM project_params WHERE id = ?");
    query.addBindValue(paramId);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления параметра проекта: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QList<ProjectParamData> DataBaseController::getAllProjectParams()
{
    QList<ProjectParamData> params;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        qDebug() << "DataBaseController: База данных не открыта для загрузки параметров проекта";
        return params;
    }
    
    qDebug() << "DataBaseController: Загружаем параметры проекта из БД";
    
    QSqlQuery query = prepareQuery("SELECT id, name, value FROM project_params ORDER BY name");
    
    if (!query.exec()) {
        setLastError("Ошибка получения параметров проекта: " + query.lastError().text());
        qDebug() << "DataBaseController: Ошибка запроса параметров проекта:" << query.lastError().text();
        return params;
    }
    
    while (query.next()) {
        ProjectParamData param;
        param.id = query.value(0).toInt();
        param.name = query.value(1).toString();
        param.value = query.value(2).toString();
        params.append(param);
        
        qDebug() << "DataBaseController: Загружен параметр проекта:" << param.name << "=" << param.value;
    }
    
    qDebug() << "DataBaseController: Всего загружено параметров проекта:" << params.size();
    return params;
}

ProjectParamData DataBaseController::getProjectParam(int paramId)
{
    ProjectParamData param;
    QSqlQuery query = prepareQuery("SELECT id, name, value FROM project_params WHERE id = ?");
    query.addBindValue(paramId);
    
    if (!query.exec() || !query.next()) {
        return param;
    }
    
    param.id = query.value(0).toInt();
    param.name = query.value(1).toString();
    param.value = query.value(2).toString();
    
    return param;
}

bool DataBaseController::setProjectParam(const QString &name, const QString &value)
{
    // Проверяем, существует ли уже параметр с таким именем
    QSqlQuery checkQuery = prepareQuery("SELECT id FROM project_params WHERE name = ?");
    checkQuery.addBindValue(name);
    
    if (checkQuery.exec() && checkQuery.next()) {
        // Обновляем существующий параметр
        int paramId = checkQuery.value(0).toInt();
        return updateProjectParam(paramId, name, value);
    } else {
        // Добавляем новый параметр
        return addProjectParam(name, value) != -1;
    }
}

bool DataBaseController::isDatabaseOpen() const
{
    return m_database.isOpen();
}

QString DataBaseController::lastError() const
{
    return m_lastError;
}

QString DataBaseController::getDatabasePath() const
{
    return m_database.databaseName();
}

bool DataBaseController::executeQuery(const QString &query, const QVariantMap &params)
{
    QSqlQuery sqlQuery = prepareQuery(query);
    
    for (auto it = params.begin(); it != params.end(); ++it) {
        sqlQuery.addBindValue(it.value());
    }
    
    if (!sqlQuery.exec()) {
        setLastError("Ошибка выполнения запроса: " + sqlQuery.lastError().text());
        return false;
    }
    
    return true;
}

QSqlQuery DataBaseController::prepareQuery(const QString &query)
{
    QSqlQuery sqlQuery(m_database);
    sqlQuery.prepare(query);
    return sqlQuery;
}

void DataBaseController::setLastError(const QString &error)
{
    m_lastError = error;
    emit databaseError(error);
}

void DataBaseController::clearAllData()
{
    QSqlQuery query(m_database);
    query.exec("DELETE FROM component_properties");
    query.exec("DELETE FROM component_variants");
    query.exec("DELETE FROM variant_properties");
    query.exec("DELETE FROM project_params");
    query.exec("DELETE FROM project_settings"); // Added for project settings
    query.exec("DELETE FROM diel_materials"); // Added for PCB materials
    query.exec("DELETE FROM pcb_data"); // Added for PCB data
    query.exec("DELETE FROM components");
    query.exec("DELETE FROM variants");
}

// Пакетная вставка компонентов (оптимизация)
bool DataBaseController::beginTransaction()
{
    QSqlQuery query(m_database);
    return query.exec("BEGIN TRANSACTION");
}

bool DataBaseController::commitTransaction()
{
    QSqlQuery query(m_database);
    return query.exec("COMMIT");
}

bool DataBaseController::rollbackTransaction()
{
    QSqlQuery query(m_database);
    return query.exec("ROLLBACK");
}

bool DataBaseController::addComponentBatch(const QString &designator, const QMap<QString, QString> &properties)
{
    // Добавляем компонент
    QSqlQuery query(m_database);
    query.prepare("INSERT INTO components (designator) VALUES (?)");
    query.addBindValue(designator);
    
    if (!query.exec()) {
        setLastError("Ошибка добавления компонента: " + query.lastError().text());
        return false;
    }
    
    int componentId = query.lastInsertId().toInt();
    
    // Добавляем свойства пакетно
    if (!properties.isEmpty()) {
        return addComponentPropertiesBatch(componentId, properties);
    }
    
    return true;
}

bool DataBaseController::addComponentPropertiesBatch(int componentId, const QMap<QString, QString> &properties)
{
    if (properties.isEmpty()) {
        return true;
    }
    
    // Подготавливаем пакетный INSERT
    QStringList placeholders;
    QVariantList values;
    
    for (auto it = properties.begin(); it != properties.end(); ++it) {
        placeholders.append("(?, ?, ?)");
        values.append(componentId);
        values.append(it.key());
        values.append(it.value());
    }
    
    QString queryStr = QString("INSERT INTO component_properties (component_id, property_name, property_value) VALUES %1")
                      .arg(placeholders.join(", "));
    
    QSqlQuery query(m_database);
    query.prepare(queryStr);
    
    for (const QVariant &value : values) {
        query.addBindValue(value);
    }
    
    if (!query.exec()) {
        setLastError("Ошибка пакетной вставки свойств: " + query.lastError().text());
        return false;
    }
    
    return true;
}

bool DataBaseController::addComponentVariantsBatch(int componentId, const QStringList &variantNames)
{
    if (variantNames.isEmpty()) {
        return true;
    }
    
    // Получаем ID вариантов
    QList<int> variantIds;
    for (const QString &variantName : variantNames) {
        int variantId = getVariantId(variantName);
        if (variantId != -1) {
            variantIds.append(variantId);
        }
    }
    
    if (variantIds.isEmpty()) {
        return true;
    }
    
    // Подготавливаем пакетный INSERT
    QStringList placeholders;
    QVariantList values;
    
    for (int variantId : variantIds) {
        placeholders.append("(?, ?, 1)");
        values.append(componentId);
        values.append(variantId);
    }
    
    QString queryStr = QString("INSERT INTO component_variants (component_id, variant_id, is_fitted) VALUES %1")
                      .arg(placeholders.join(", "));
    
    QSqlQuery query(m_database);
    query.prepare(queryStr);
    
    for (const QVariant &value : values) {
        query.addBindValue(value);
    }
    
    if (!query.exec()) {
        setLastError("Ошибка пакетной вставки вариантов: " + query.lastError().text());
        return false;
    }
    
    return true;
}

// Методы для работы с настройками проекта
bool DataBaseController::setProjectSetting(const QString &key, const QString &value)
{
    QSqlQuery query = prepareQuery("INSERT OR REPLACE INTO project_settings (key, value) VALUES (?, ?)");
    query.addBindValue(key);
    query.addBindValue(value);
    
    if (!query.exec()) {
        setLastError("Ошибка сохранения настройки проекта: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QString DataBaseController::getProjectSetting(const QString &key, const QString &defaultValue)
{
    QSqlQuery query = prepareQuery("SELECT value FROM project_settings WHERE key = ?");
    query.addBindValue(key);
    
    if (!query.exec()) {
        setLastError("Ошибка получения настройки проекта: " + query.lastError().text());
        return defaultValue;
    }
    
    if (query.next()) {
        return query.value(0).toString();
    }
    
    return defaultValue;
}

bool DataBaseController::setProjectSettingList(const QString &key, const QStringList &value)
{
    // Сохраняем список как JSON строку
    QJsonArray array;
    for (const QString &item : value) {
        array.append(item);
    }
    
    QJsonDocument doc(array);
    QString jsonString = doc.toJson(QJsonDocument::Compact);
    
    return setProjectSetting(key, jsonString);
}

QStringList DataBaseController::getProjectSettingList(const QString &key, const QStringList &defaultValue)
{
    QString jsonString = getProjectSetting(key, QString());
    
    if (jsonString.isEmpty()) {
        return defaultValue;
    }
    
    QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8());
    if (!doc.isArray()) {
        return defaultValue;
    }
    
    QStringList result;
    QJsonArray array = doc.array();
    for (const QJsonValue &value : array) {
        result.append(value.toString());
    }
    
    return result;
}

// Методы для работы с маппингами дезигнаторов
int DataBaseController::addDesignatorMapping(const QString &designator, const QString &singularName, 
                                           const QString &pluralName, bool isCustom)
{
    QSqlQuery query = prepareQuery("INSERT INTO designator_mappings (designator, singular_name, plural_name, is_custom) VALUES (?, ?, ?, ?)");
    query.addBindValue(designator);
    query.addBindValue(singularName);
    query.addBindValue(pluralName);
    query.addBindValue(isCustom);
    
    if (!query.exec()) {
        setLastError("Ошибка добавления маппинга дезигнатора: " + query.lastError().text());
        return -1;
    }
    
    emit dataChanged();
    return query.lastInsertId().toInt();
}

bool DataBaseController::updateDesignatorMapping(int mappingId, const QString &designator, 
                                               const QString &singularName, const QString &pluralName, bool isCustom)
{
    QSqlQuery query = prepareQuery("UPDATE designator_mappings SET designator = ?, singular_name = ?, plural_name = ?, is_custom = ? WHERE id = ?");
    query.addBindValue(designator);
    query.addBindValue(singularName);
    query.addBindValue(pluralName);
    query.addBindValue(isCustom);
    query.addBindValue(mappingId);
    
    if (!query.exec()) {
        setLastError("Ошибка обновления маппинга дезигнатора: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

bool DataBaseController::removeDesignatorMapping(int mappingId)
{
    QSqlQuery query = prepareQuery("DELETE FROM designator_mappings WHERE id = ?");
    query.addBindValue(mappingId);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления маппинга дезигнатора: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

bool DataBaseController::removeDesignatorMapping(const QString &designator)
{
    QSqlQuery query = prepareQuery("DELETE FROM designator_mappings WHERE designator = ?");
    query.addBindValue(designator);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления маппинга дезигнатора: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QList<DesignatorMappingData> DataBaseController::getAllDesignatorMappings()
{
    QList<DesignatorMappingData> mappings;
    
    QSqlQuery query = prepareQuery("SELECT id, designator, singular_name, plural_name, is_custom FROM designator_mappings ORDER BY designator");
    
    if (!query.exec()) {
        setLastError("Ошибка получения маппингов дезигнаторов: " + query.lastError().text());
        return mappings;
    }
    
    while (query.next()) {
        DesignatorMappingData mapping;
        mapping.id = query.value(0).toInt();
        mapping.designator = query.value(1).toString();
        mapping.singularName = query.value(2).toString();
        mapping.pluralName = query.value(3).toString();
        mapping.isCustom = query.value(4).toBool();
        mappings.append(mapping);
    }
    
    return mappings;
}

DesignatorMappingData DataBaseController::getDesignatorMapping(int mappingId)
{
    DesignatorMappingData mapping;
    mapping.id = -1;
    
    QSqlQuery query = prepareQuery("SELECT id, designator, singular_name, plural_name, is_custom FROM designator_mappings WHERE id = ?");
    query.addBindValue(mappingId);
    
    if (!query.exec()) {
        setLastError("Ошибка получения маппинга дезигнатора: " + query.lastError().text());
        return mapping;
    }
    
    if (query.next()) {
        mapping.id = query.value(0).toInt();
        mapping.designator = query.value(1).toString();
        mapping.singularName = query.value(2).toString();
        mapping.pluralName = query.value(3).toString();
        mapping.isCustom = query.value(4).toBool();
    }
    
    return mapping;
}

DesignatorMappingData DataBaseController::getDesignatorMapping(const QString &designator)
{
    DesignatorMappingData mapping;
    mapping.id = -1;
    
    QSqlQuery query = prepareQuery("SELECT id, designator, singular_name, plural_name, is_custom FROM designator_mappings WHERE designator = ?");
    query.addBindValue(designator);
    
    if (!query.exec()) {
        setLastError("Ошибка получения маппинга дезигнатора: " + query.lastError().text());
        return mapping;
    }
    
    if (query.next()) {
        mapping.id = query.value(0).toInt();
        mapping.designator = query.value(1).toString();
        mapping.singularName = query.value(2).toString();
        mapping.pluralName = query.value(3).toString();
        mapping.isCustom = query.value(4).toBool();
    }
    
    return mapping;
}

bool DataBaseController::saveDesignatorMappings(const QList<DesignatorMappingData> &mappings)
{
    // Начинаем транзакцию
    if (!beginTransaction()) {
        return false;
    }
    
    // Очищаем все существующие маппинги
    QSqlQuery clearQuery = prepareQuery("DELETE FROM designator_mappings");
    if (!clearQuery.exec()) {
        setLastError("Ошибка очистки маппингов дезигнаторов: " + clearQuery.lastError().text());
        rollbackTransaction();
        return false;
    }
    
    // Добавляем новые маппинги
    for (const auto &mapping : mappings) {
        QSqlQuery insertQuery = prepareQuery("INSERT INTO designator_mappings (designator, singular_name, plural_name, is_custom) VALUES (?, ?, ?, ?)");
        insertQuery.addBindValue(mapping.designator);
        insertQuery.addBindValue(mapping.singularName);
        insertQuery.addBindValue(mapping.pluralName);
        insertQuery.addBindValue(mapping.isCustom);
        
        if (!insertQuery.exec()) {
            setLastError("Ошибка сохранения маппинга дезигнатора: " + insertQuery.lastError().text());
            rollbackTransaction();
            return false;
        }
    }
    
    // Подтверждаем транзакцию
    if (!commitTransaction()) {
        return false;
    }
    
    emit dataChanged();
    return true;
}

bool DataBaseController::clearCustomDesignatorMappings()
{
    QSqlQuery query = prepareQuery("DELETE FROM designator_mappings WHERE is_custom = 1");
    
    if (!query.exec()) {
        setLastError("Ошибка очистки пользовательских маппингов: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

bool DataBaseController::resetDesignatorMappingsToDefaults()
{
    // Сначала очищаем все маппинги
    QSqlQuery clearQuery = prepareQuery("DELETE FROM designator_mappings");
    if (!clearQuery.exec()) {
        setLastError("Ошибка очистки маппингов дезигнаторов: " + clearQuery.lastError().text());
        return false;
    }
    
    // Добавляем значения по умолчанию
    QList<DesignatorMappingData> defaultMappings = {
        {1, "A", "Устройство (общее обозначение)", "Устройства (общее обозначение)", false},
        {2, "B", "Преобразователи неэлектрических величин в электрические", "Преобразователи неэлектрических величин в электрические", false},
        {3, "C", "Конденсаторы", "Конденсаторы", false},
        {4, "D", "Схемы интегральные, микросборки", "Схемы интегральные, микросборки", false},
        {5, "E", "Элементы разные", "Элементы разные", false},
        {6, "F", "Защитные аппараты, предохранители, разрядники", "Защитные аппараты, предохранители, разрядники", false},
        {7, "G", "Генераторы, источники питания", "Генераторы, источники питания", false},
        {8, "H", "Устройства индикаторные и сигнальные", "Устройства индикаторные и сигнальные", false},
        {9, "K", "Реле", "Реле", false},
        {10, "L", "Катушки индуктивности, дроссели", "Катушки индуктивности, дроссели", false},
        {11, "M", "Двигатели", "Двигатели", false},
        {12, "P", "Приборы измерительные", "Приборы измерительные", false},
        {13, "Q", "Выключатели и разъединители в силовых цепях", "Выключатели и разъединители в силовых цепях", false},
        {14, "R", "Резисторы", "Резисторы", false},
        {15, "S", "Устройства коммутационные в цепях управления, сигнализации и измерительных", "Устройства коммутационные в цепях управления, сигнализации и измерительных", false},
        {16, "T", "Трансформаторы, автотрансформаторы", "Трансформаторы, автотрансформаторы", false},
        {17, "U", "Преобразователи электрических величин в электрические", "Преобразователи электрических величин в электрические", false},
        {18, "V", "Приборы электровакуумные и полупроводниковые", "Приборы электровакуумные и полупроводниковые", false},
        {19, "W", "Линии и элементы сверхвысоких частот", "Линии и элементы сверхвысоких частот", false},
        {20, "X", "Соединения контактные", "Соединения контактные", false},
        {21, "Y", "Устройства механические с электромагнитным приводом", "Устройства механические с электромагнитным приводом", false},
        {22, "Z", "Ограничители, устройства оконечные, фильтры", "Ограничители, устройства оконечные, фильтры", false},
        {23, "BA", "Громкоговорители", "Громкоговорители", false},
        {24, "BB", "Преобразователи неэлектрических величин в электрические", "Преобразователи неэлектрических величин в электрические", false},
        {25, "BZ", "Преобразователи неэлектрических величин в электрические", "Преобразователи неэлектрических величин в электрические", false}
    };
    
    return saveDesignatorMappings(defaultMappings);
}

// Работа с надписями титульного листа
bool DataBaseController::saveTitleInscriptions(const QMap<int, QString> &inscriptions, const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    qDebug() << "DataBaseController::saveTitleInscriptions: Сохраняем надписи для проекта:" << projectName;
    qDebug() << "DataBaseController::saveTitleInscriptions: Путь к БД:" << m_database.databaseName();
    qDebug() << "DataBaseController::saveTitleInscriptions: Количество полей для сохранения:" << inscriptions.size();
    
    // Начинаем транзакцию
    if (!beginTransaction()) {
        return false;
    }
    
    // Удаляем существующие записи для данного проекта
    QSqlQuery deleteQuery = prepareQuery("DELETE FROM title_inscriptions WHERE project_name = ?");
    deleteQuery.addBindValue(projectName);
    if (!deleteQuery.exec()) {
        setLastError("Ошибка удаления существующих надписей: " + deleteQuery.lastError().text());
        qDebug() << "DataBaseController::saveTitleInscriptions: Ошибка удаления:" << deleteQuery.lastError().text();
        rollbackTransaction();
        return false;
    }
    
    // Добавляем новые записи
    int savedCount = 0;
    for (auto it = inscriptions.begin(); it != inscriptions.end(); ++it) {
        if (!it.value().isEmpty()) { // Сохраняем только непустые значения
            QSqlQuery insertQuery = prepareQuery(
                "INSERT INTO title_inscriptions (project_name, field_number, field_value) VALUES (?, ?, ?)"
            );
            insertQuery.addBindValue(projectName);
            insertQuery.addBindValue(it.key());
            insertQuery.addBindValue(it.value());
            
            if (!insertQuery.exec()) {
                setLastError("Ошибка сохранения надписи: " + insertQuery.lastError().text());
                qDebug() << "DataBaseController::saveTitleInscriptions: Ошибка сохранения поля" << it.key() << ":" << insertQuery.lastError().text();
                rollbackTransaction();
                return false;
            }
            savedCount++;
            qDebug() << "DataBaseController::saveTitleInscriptions: Сохранено поле" << it.key() << "=" << it.value();
        }
    }
    
    // Подтверждаем транзакцию
    if (!commitTransaction()) {
        return false;
    }
    
    qDebug() << "DataBaseController::saveTitleInscriptions: Всего сохранено полей:" << savedCount;
    emit dataChanged();
    return true;
}

bool DataBaseController::loadTitleInscriptions(QMap<int, QString> &inscriptions, const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    inscriptions.clear();
    
    qDebug() << "DataBaseController::loadTitleInscriptions: Загружаем надписи для проекта:" << projectName;
    qDebug() << "DataBaseController::loadTitleInscriptions: Путь к БД:" << m_database.databaseName();
    
    QSqlQuery query = prepareQuery(
        "SELECT field_number, field_value FROM title_inscriptions WHERE project_name = ? ORDER BY field_number"
    );
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка загрузки надписей: " + query.lastError().text());
        qDebug() << "DataBaseController::loadTitleInscriptions: Ошибка выполнения запроса:" << query.lastError().text();
        return false;
    }
    
    int count = 0;
    while (query.next()) {
        int fieldNumber = query.value(0).toInt();
        QString fieldValue = query.value(1).toString();
        inscriptions[fieldNumber] = fieldValue;
        count++;
        qDebug() << "DataBaseController::loadTitleInscriptions: Загружено поле" << fieldNumber << "=" << fieldValue;
    }
    
    qDebug() << "DataBaseController::loadTitleInscriptions: Всего загружено полей:" << count;
    return true;
}

bool DataBaseController::deleteTitleInscriptions(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    QSqlQuery query = prepareQuery("DELETE FROM title_inscriptions WHERE project_name = ?");
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления надписей: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QStringList DataBaseController::getAvailableTitleInscriptionProjects()
{
    QStringList projects;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return projects;
    }
    
    QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM title_inscriptions ORDER BY project_name");
    
    if (!query.exec()) {
        setLastError("Ошибка получения списка проектов: " + query.lastError().text());
        return projects;
    }
    
    while (query.next()) {
        projects << query.value(0).toString();
    }
    
    return projects;
}

// Работа с перечнем элементов
bool DataBaseController::savePerechenTable(const QByteArray &tableData, const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    qDebug() << "DataBaseController::savePerechenTable: Сохраняем перечень для проекта:" << projectName;
    
    // Начинаем транзакцию
    if (!beginTransaction()) {
        return false;
    }
    
    // Удаляем существующие записи для данного проекта
    QSqlQuery deleteQuery = prepareQuery("DELETE FROM perechen_rows WHERE project_name = ?");
    deleteQuery.addBindValue(projectName);
    if (!deleteQuery.exec()) {
        setLastError("Ошибка удаления существующего перечня: " + deleteQuery.lastError().text());
        qDebug() << "DataBaseController::savePerechenTable: Ошибка удаления:" << deleteQuery.lastError().text();
        rollbackTransaction();
        return false;
    }
    
    // Парсим JSON данные и сохраняем каждую строку отдельно
    QJsonDocument doc = QJsonDocument::fromJson(tableData);
    if (!doc.isObject()) {
        setLastError("Ошибка парсинга JSON данных перечня");
        rollbackTransaction();
        return false;
    }
    
    QJsonObject root = doc.object();
    QJsonArray rowsArray = root["rows"].toArray();
    
    int rowOrder = 0;
    for (const QJsonValue &value : rowsArray) {
        QJsonObject rowObj = value.toObject();
        
        // Получаем данные ячеек
        QJsonObject positionObj = rowObj["position"].toObject();
        QJsonObject designationObj = rowObj["designation"].toObject();
        QJsonObject quantityObj = rowObj["quantity"].toObject();
        QJsonObject noteObj = rowObj["note"].toObject();
        
        // Формируем JSON объект с настройками ячеек (stretch, isHeader, isUnderline)
        QJsonObject cellSettingsObj;
        
        QJsonObject positionCellObj;
        positionCellObj["stretch"] = positionObj["stretch"].toInt(100);
        positionCellObj["isHeader"] = positionObj["isHeader"].toBool(false);
        positionCellObj["isUnderline"] = positionObj["isUnderline"].toBool(false);
        cellSettingsObj["position"] = positionCellObj;
        
        QJsonObject designationCellObj;
        designationCellObj["stretch"] = designationObj["stretch"].toInt(100);
        designationCellObj["isHeader"] = designationObj["isHeader"].toBool(false);
        designationCellObj["isUnderline"] = designationObj["isUnderline"].toBool(false);
        cellSettingsObj["designation"] = designationCellObj;
        
        QJsonObject quantityCellObj;
        quantityCellObj["stretch"] = quantityObj["stretch"].toInt(100);
        quantityCellObj["isHeader"] = quantityObj["isHeader"].toBool(false);
        quantityCellObj["isUnderline"] = quantityObj["isUnderline"].toBool(false);
        cellSettingsObj["quantity"] = quantityCellObj;
        
        QJsonObject noteCellObj;
        noteCellObj["stretch"] = noteObj["stretch"].toInt(100);
        noteCellObj["isHeader"] = noteObj["isHeader"].toBool(false);
        noteCellObj["isUnderline"] = noteObj["isUnderline"].toBool(false);
        cellSettingsObj["note"] = noteCellObj;
        
        QJsonDocument cellSettingsDoc(cellSettingsObj);
        QString cellSettingsJson = cellSettingsDoc.toJson(QJsonDocument::Compact);
        
        // Добавляем строку в БД
        QSqlQuery insertQuery = prepareQuery(
            "INSERT INTO perechen_rows (project_name, row_order, position_value, designation_value, quantity_value, note_value, "
            "is_header, is_empty, position_is_auto, designation_is_auto, quantity_is_auto, note_is_auto, cell_stretches) "
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
        );
        
        insertQuery.addBindValue(projectName);
        insertQuery.addBindValue(rowOrder++);
        insertQuery.addBindValue(positionObj["value"].toString());
        insertQuery.addBindValue(designationObj["value"].toString());
        insertQuery.addBindValue(quantityObj["value"].toString());
        insertQuery.addBindValue(noteObj["value"].toString());
        insertQuery.addBindValue(rowObj["isHeader"].toBool());
        insertQuery.addBindValue(rowObj["isEmpty"].toBool());
        insertQuery.addBindValue(positionObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(designationObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(quantityObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(noteObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(cellSettingsJson);
        
        if (!insertQuery.exec()) {
            setLastError("Ошибка сохранения строки перечня: " + insertQuery.lastError().text());
            qDebug() << "DataBaseController::savePerechenTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text();
            rollbackTransaction();
            return false;
        }
    }
    
    // Подтверждаем транзакцию
    if (!commitTransaction()) {
        return false;
    }
    
    qDebug() << "DataBaseController::savePerechenTable: Перечень успешно сохранен," << rowsArray.size() << "строк";
    emit dataChanged();
    return true;
}

QByteArray DataBaseController::loadPerechenTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QByteArray();
    }
    
    qDebug() << "DataBaseController::loadPerechenTable: Загружаем перечень для проекта:" << projectName;
    
    QSqlQuery query = prepareQuery(
        "SELECT row_order, position_value, designation_value, quantity_value, note_value, "
        "is_header, is_empty, position_is_auto, designation_is_auto, quantity_is_auto, note_is_auto, cell_stretches "
        "FROM perechen_rows WHERE project_name = ? ORDER BY row_order"
    );
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка загрузки перечня: " + query.lastError().text());
        qDebug() << "DataBaseController::loadPerechenTable: Ошибка выполнения запроса:" << query.lastError().text();
        return QByteArray();
    }
    
    // Создаем JSON структуру для совместимости с PerechenTableModel
    QJsonObject root;
    QJsonArray rowsArray;
    
    while (query.next()) {
        QJsonObject rowObj;
        
        // Загружаем настройки ячеек (stretch, isHeader, isUnderline) из JSON
        QJsonObject cellSettingsObj;
        QString cellSettingsJson = query.value(11).toString();
        if (!cellSettingsJson.isEmpty()) {
            QJsonDocument cellSettingsDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8());
            if (cellSettingsDoc.isObject()) {
                cellSettingsObj = cellSettingsDoc.object();
            }
        }
        
        // Получаем настройки для каждой ячейки (с fallback на старый формат массива)
        QJsonObject positionCellObj = cellSettingsObj["position"].toObject();
        QJsonObject designationCellObj = cellSettingsObj["designation"].toObject();
        QJsonObject quantityCellObj = cellSettingsObj["quantity"].toObject();
        QJsonObject noteCellObj = cellSettingsObj["note"].toObject();
        
        // Если старый формат (массив), конвертируем
        if (positionCellObj.isEmpty() && cellSettingsJson.startsWith("[")) {
            QJsonDocument oldDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8());
            if (oldDoc.isArray()) {
                QJsonArray stretchesArray = oldDoc.array();
                if (stretchesArray.size() > 0) {
                    positionCellObj["stretch"] = stretchesArray[0].toInt(100);
                    positionCellObj["isHeader"] = false;
                    positionCellObj["isUnderline"] = false;
                }
                if (stretchesArray.size() > 1) {
                    designationCellObj["stretch"] = stretchesArray[1].toInt(100);
                    designationCellObj["isHeader"] = false;
                    designationCellObj["isUnderline"] = false;
                }
                if (stretchesArray.size() > 2) {
                    quantityCellObj["stretch"] = stretchesArray[2].toInt(100);
                    quantityCellObj["isHeader"] = false;
                    quantityCellObj["isUnderline"] = false;
                }
                if (stretchesArray.size() > 3) {
                    noteCellObj["stretch"] = stretchesArray[3].toInt(100);
                    noteCellObj["isHeader"] = false;
                    noteCellObj["isUnderline"] = false;
                }
            }
        }
        
        // Создаем объекты для каждой ячейки
        QJsonObject positionObj;
        positionObj["value"] = query.value(1).toString();
        positionObj["rowNumber"] = query.value(0).toInt();
        positionObj["pageNumber"] = 1;
        positionObj["isHeader"] = positionCellObj["isHeader"].toBool(query.value(5).toBool());
        positionObj["isAutoGenerated"] = query.value(7).toBool();
        positionObj["isEmpty"] = query.value(1).toString().isEmpty();
        positionObj["stretch"] = positionCellObj["stretch"].toInt(100);
        positionObj["isUnderline"] = positionCellObj["isUnderline"].toBool(false);
        
        QJsonObject designationObj;
        designationObj["value"] = query.value(2).toString();
        designationObj["rowNumber"] = query.value(0).toInt();
        designationObj["pageNumber"] = 1;
        designationObj["isHeader"] = designationCellObj["isHeader"].toBool(query.value(5).toBool());
        designationObj["isAutoGenerated"] = query.value(8).toBool();
        designationObj["isEmpty"] = query.value(2).toString().isEmpty();
        designationObj["stretch"] = designationCellObj["stretch"].toInt(100);
        designationObj["isUnderline"] = designationCellObj["isUnderline"].toBool(false);
        
        QJsonObject quantityObj;
        quantityObj["value"] = query.value(3).toString();
        quantityObj["rowNumber"] = query.value(0).toInt();
        quantityObj["pageNumber"] = 1;
        quantityObj["isHeader"] = quantityCellObj["isHeader"].toBool(query.value(5).toBool());
        quantityObj["isAutoGenerated"] = query.value(9).toBool();
        quantityObj["isEmpty"] = query.value(3).toString().isEmpty();
        quantityObj["stretch"] = quantityCellObj["stretch"].toInt(100);
        quantityObj["isUnderline"] = quantityCellObj["isUnderline"].toBool(false);
        
        QJsonObject noteObj;
        noteObj["value"] = query.value(4).toString();
        noteObj["rowNumber"] = query.value(0).toInt();
        noteObj["pageNumber"] = 1;
        noteObj["isHeader"] = noteCellObj["isHeader"].toBool(query.value(5).toBool());
        noteObj["isAutoGenerated"] = query.value(10).toBool();
        noteObj["isEmpty"] = query.value(4).toString().isEmpty();
        noteObj["stretch"] = noteCellObj["stretch"].toInt(100);
        noteObj["isUnderline"] = noteCellObj["isUnderline"].toBool(false);
        
        // Создаем объект строки
        rowObj["position"] = positionObj;
        rowObj["designation"] = designationObj;
        rowObj["quantity"] = quantityObj;
        rowObj["note"] = noteObj;
        rowObj["isHeader"] = query.value(5).toBool();
        rowObj["isEmpty"] = query.value(6).toBool();
        rowObj["rowNumber"] = query.value(0).toInt();
        rowObj["pageNumber"] = 1;
        
        rowsArray.append(rowObj);
    }
    
    root["rows"] = rowsArray;
    root["columnMappings"] = QJsonArray::fromStringList(QStringList() << "<Авто>" << "Designator" << "<Пусто>" << "<Пусто>");
    root["propertyNames"] = QJsonArray::fromStringList(QStringList() << "Designator");
    
    QJsonDocument doc(root);
    QByteArray result = doc.toJson();
    
    qDebug() << "DataBaseController::loadPerechenTable: Загружено" << rowsArray.size() << "строк";
    return result;
}

bool DataBaseController::deletePerechenTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    QSqlQuery query = prepareQuery("DELETE FROM perechen_rows WHERE project_name = ?");
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления перечня: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QStringList DataBaseController::getAvailablePerechenProjects()
{
    QStringList projects;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return projects;
    }
    
    QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM perechen_rows ORDER BY project_name");
    
    if (!query.exec()) {
        setLastError("Ошибка получения списка проектов перечня: " + query.lastError().text());
        return projects;
    }
    
    while (query.next()) {
        projects << query.value(0).toString();
    }
    
    return projects;
}

QString DataBaseController::getPerechenTableInfo(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QString();
    }
    
    QString actualProjectName = projectName;
    if (actualProjectName.isEmpty()) {
        actualProjectName = QFileInfo(m_database.databaseName()).baseName();
    }
    
    QSqlQuery query = prepareQuery(
        "SELECT row_order, position_value, designation_value, quantity_value, note_value, "
        "is_header, is_empty, position_is_auto, designation_is_auto, quantity_is_auto, note_is_auto "
        "FROM perechen_rows WHERE project_name = ? ORDER BY row_order"
    );
    query.addBindValue(actualProjectName);
    
    if (!query.exec()) {
        setLastError("Ошибка получения информации о перечне: " + query.lastError().text());
        return QString();
    }
    
    QString info = QString("Информация о перечне для проекта '%1':\n").arg(actualProjectName);
    info += QString("Всего строк: %1\n\n").arg(query.size());
    
    while (query.next()) {
        int rowOrder = query.value(0).toInt();
        QString position = query.value(1).toString();
        QString designation = query.value(2).toString();
        QString quantity = query.value(3).toString();
        QString note = query.value(4).toString();
        bool isHeader = query.value(5).toBool();
        bool isEmpty = query.value(6).toBool();
        bool posAuto = query.value(7).toBool();
        bool desAuto = query.value(8).toBool();
        bool qtyAuto = query.value(9).toBool();
        bool noteAuto = query.value(10).toBool();
        
        info += QString("Строка %1:\n").arg(rowOrder);
        info += QString("  Поз.: '%1' (авто: %2)\n").arg(position).arg(posAuto ? "да" : "нет");
        info += QString("  Наим.: '%1' (авто: %2)\n").arg(designation).arg(desAuto ? "да" : "нет");
        info += QString("  Кол.: '%1' (авто: %2)\n").arg(quantity).arg(qtyAuto ? "да" : "нет");
        info += QString("  Прим.: '%1' (авто: %2)\n").arg(note).arg(noteAuto ? "да" : "нет");
        info += QString("  Заголовок: %1, Пустая: %2\n\n").arg(isHeader ? "да" : "нет").arg(isEmpty ? "да" : "нет");
    }
    
    return info;
}

// Работа со спецификацией платы
bool DataBaseController::saveSpecificationPCBTable(const QByteArray &tableData, const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    qDebug() << "DataBaseController::saveSpecificationPCBTable: Сохраняем спецификацию платы для проекта:" << projectName;
    
    // Начинаем транзакцию
    if (!beginTransaction()) {
        return false;
    }
    
    // Удаляем существующие записи для данного проекта
    QSqlQuery deleteQuery = prepareQuery("DELETE FROM specification_pcb_rows WHERE project_name = ?");
    deleteQuery.addBindValue(projectName);
    if (!deleteQuery.exec()) {
        setLastError("Ошибка удаления существующей спецификации платы: " + deleteQuery.lastError().text());
        qDebug() << "DataBaseController::saveSpecificationPCBTable: Ошибка удаления:" << deleteQuery.lastError().text();
        rollbackTransaction();
        return false;
    }
    
    // Парсим JSON данные и сохраняем каждую строку отдельно
    QJsonDocument doc = QJsonDocument::fromJson(tableData);
    if (!doc.isObject()) {
        setLastError("Ошибка парсинга JSON данных спецификации платы");
        rollbackTransaction();
        return false;
    }
    
    QJsonObject root = doc.object();
    QJsonArray rowsArray = root["rows"].toArray();
    
    int rowOrder = 0;
    for (const QJsonValue &value : rowsArray) {
        QJsonObject rowObj = value.toObject();
        
        // Получаем данные ячеек для 7 столбцов
        QJsonObject formatObj = rowObj["format"].toObject();
        QJsonObject zoneObj = rowObj["zone"].toObject();
        QJsonObject positionObj = rowObj["position"].toObject();
        QJsonObject designationObj = rowObj["designation"].toObject();
        QJsonObject nameObj = rowObj["name"].toObject();
        QJsonObject quantityObj = rowObj["quantity"].toObject();
        QJsonObject noteObj = rowObj["note"].toObject();
        
        // Формируем JSON объект с настройками ячеек (stretch, isHeader, isUnderline)
        QJsonObject cellSettingsObj;
        
        QJsonObject formatCellObj;
        formatCellObj["stretch"] = formatObj["stretch"].toInt(100);
        formatCellObj["isHeader"] = formatObj["isHeader"].toBool(false);
        formatCellObj["isUnderline"] = formatObj["isUnderline"].toBool(false);
        cellSettingsObj["format"] = formatCellObj;
        
        QJsonObject zoneCellObj;
        zoneCellObj["stretch"] = zoneObj["stretch"].toInt(100);
        zoneCellObj["isHeader"] = zoneObj["isHeader"].toBool(false);
        zoneCellObj["isUnderline"] = zoneObj["isUnderline"].toBool(false);
        cellSettingsObj["zone"] = zoneCellObj;
        
        QJsonObject positionCellObj;
        positionCellObj["stretch"] = positionObj["stretch"].toInt(100);
        positionCellObj["isHeader"] = positionObj["isHeader"].toBool(false);
        positionCellObj["isUnderline"] = positionObj["isUnderline"].toBool(false);
        cellSettingsObj["position"] = positionCellObj;
        
        QJsonObject designationCellObj;
        designationCellObj["stretch"] = designationObj["stretch"].toInt(100);
        designationCellObj["isHeader"] = designationObj["isHeader"].toBool(false);
        designationCellObj["isUnderline"] = designationObj["isUnderline"].toBool(false);
        cellSettingsObj["designation"] = designationCellObj;
        
        QJsonObject nameCellObj;
        nameCellObj["stretch"] = nameObj["stretch"].toInt(100);
        nameCellObj["isHeader"] = nameObj["isHeader"].toBool(false);
        nameCellObj["isUnderline"] = nameObj["isUnderline"].toBool(false);
        cellSettingsObj["name"] = nameCellObj;
        
        QJsonObject quantityCellObj;
        quantityCellObj["stretch"] = quantityObj["stretch"].toInt(100);
        quantityCellObj["isHeader"] = quantityObj["isHeader"].toBool(false);
        quantityCellObj["isUnderline"] = quantityObj["isUnderline"].toBool(false);
        cellSettingsObj["quantity"] = quantityCellObj;
        
        QJsonObject noteCellObj;
        noteCellObj["stretch"] = noteObj["stretch"].toInt(100);
        noteCellObj["isHeader"] = noteObj["isHeader"].toBool(false);
        noteCellObj["isUnderline"] = noteObj["isUnderline"].toBool(false);
        cellSettingsObj["note"] = noteCellObj;
        
        QJsonDocument cellSettingsDoc(cellSettingsObj);
        QString cellSettingsJson = cellSettingsDoc.toJson(QJsonDocument::Compact);
        
        // Добавляем строку в БД
        QSqlQuery insertQuery = prepareQuery(
            "INSERT INTO specification_pcb_rows (project_name, row_order, format_value, zone_value, position_value, "
            "designation_value, name_value, quantity_value, note_value, is_header, is_empty, "
            "format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto, cell_stretches) "
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
        );
        
        insertQuery.addBindValue(projectName);
        insertQuery.addBindValue(rowOrder++);
        insertQuery.addBindValue(formatObj["value"].toString());
        insertQuery.addBindValue(zoneObj["value"].toString());
        insertQuery.addBindValue(positionObj["value"].toString());
        insertQuery.addBindValue(designationObj["value"].toString());
        insertQuery.addBindValue(nameObj["value"].toString());
        insertQuery.addBindValue(quantityObj["value"].toString());
        insertQuery.addBindValue(noteObj["value"].toString());
        insertQuery.addBindValue(rowObj["isHeader"].toBool());
        insertQuery.addBindValue(rowObj["isEmpty"].toBool());
        insertQuery.addBindValue(formatObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(zoneObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(positionObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(designationObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(nameObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(quantityObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(noteObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(cellSettingsJson);
        
        if (!insertQuery.exec()) {
            setLastError("Ошибка сохранения строки спецификации платы: " + insertQuery.lastError().text());
            qDebug() << "DataBaseController::saveSpecificationPCBTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text();
            rollbackTransaction();
            return false;
        }
    }
    
    // Подтверждаем транзакцию
    if (!commitTransaction()) {
        return false;
    }
    
    qDebug() << "DataBaseController::saveSpecificationPCBTable: Спецификация платы успешно сохранена," << rowsArray.size() << "строк";
    emit dataChanged();
    return true;
}

QByteArray DataBaseController::loadSpecificationPCBTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QByteArray();
    }
    
    qDebug() << "DataBaseController::loadSpecificationPCBTable: Загружаем спецификацию платы для проекта:" << projectName;
    
    QSqlQuery query = prepareQuery(
        "SELECT row_order, format_value, zone_value, position_value, designation_value, name_value, quantity_value, note_value, "
        "is_header, is_empty, format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto, cell_stretches "
        "FROM specification_pcb_rows WHERE project_name = ? ORDER BY row_order"
    );
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка загрузки спецификации платы: " + query.lastError().text());
        qDebug() << "DataBaseController::loadSpecificationPCBTable: Ошибка выполнения запроса:" << query.lastError().text();
        return QByteArray();
    }
    
    // Создаем JSON структуру для совместимости с SpecificationPCBTableModel
    QJsonObject root;
    QJsonArray rowsArray;
    
    while (query.next()) {
        QJsonObject rowObj;
        
        // Загружаем настройки ячеек (stretch, isHeader, isUnderline) из JSON
        QJsonObject cellSettingsObj;
        QString cellSettingsJson = query.value(17).toString();
        if (!cellSettingsJson.isEmpty()) {
            QJsonDocument cellSettingsDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8());
            if (cellSettingsDoc.isObject()) {
                cellSettingsObj = cellSettingsDoc.object();
            }
        }
        
        // Получаем настройки для каждой ячейки
        QJsonObject formatCellObj = cellSettingsObj["format"].toObject();
        QJsonObject zoneCellObj = cellSettingsObj["zone"].toObject();
        QJsonObject positionCellObj = cellSettingsObj["position"].toObject();
        QJsonObject designationCellObj = cellSettingsObj["designation"].toObject();
        QJsonObject nameCellObj = cellSettingsObj["name"].toObject();
        QJsonObject quantityCellObj = cellSettingsObj["quantity"].toObject();
        QJsonObject noteCellObj = cellSettingsObj["note"].toObject();
        
        // Создаем объекты для каждой ячейки (7 столбцов)
        QJsonObject formatObj;
        formatObj["value"] = query.value(1).toString();
        formatObj["rowNumber"] = query.value(0).toInt();
        formatObj["pageNumber"] = 1;
        formatObj["isHeader"] = formatCellObj["isHeader"].toBool(query.value(8).toBool());
        formatObj["isAutoGenerated"] = query.value(10).toBool();
        formatObj["isEmpty"] = query.value(1).toString().isEmpty();
        formatObj["stretch"] = formatCellObj["stretch"].toInt(100);
        formatObj["isUnderline"] = formatCellObj["isUnderline"].toBool(false);
        
        QJsonObject zoneObj;
        zoneObj["value"] = query.value(2).toString();
        zoneObj["rowNumber"] = query.value(0).toInt();
        zoneObj["pageNumber"] = 1;
        zoneObj["isHeader"] = zoneCellObj["isHeader"].toBool(query.value(8).toBool());
        zoneObj["isAutoGenerated"] = query.value(11).toBool();
        zoneObj["isEmpty"] = query.value(2).toString().isEmpty();
        zoneObj["stretch"] = zoneCellObj["stretch"].toInt(100);
        zoneObj["isUnderline"] = zoneCellObj["isUnderline"].toBool(false);
        
        QJsonObject positionObj;
        positionObj["value"] = query.value(3).toString();
        positionObj["rowNumber"] = query.value(0).toInt();
        positionObj["pageNumber"] = 1;
        positionObj["isHeader"] = positionCellObj["isHeader"].toBool(query.value(8).toBool());
        positionObj["isAutoGenerated"] = query.value(12).toBool();
        positionObj["isEmpty"] = query.value(3).toString().isEmpty();
        positionObj["stretch"] = positionCellObj["stretch"].toInt(100);
        positionObj["isUnderline"] = positionCellObj["isUnderline"].toBool(false);
        
        QJsonObject designationObj;
        designationObj["value"] = query.value(4).toString();
        designationObj["rowNumber"] = query.value(0).toInt();
        designationObj["pageNumber"] = 1;
        designationObj["isHeader"] = designationCellObj["isHeader"].toBool(query.value(8).toBool());
        designationObj["isAutoGenerated"] = query.value(13).toBool();
        designationObj["isEmpty"] = query.value(4).toString().isEmpty();
        designationObj["stretch"] = designationCellObj["stretch"].toInt(100);
        designationObj["isUnderline"] = designationCellObj["isUnderline"].toBool(false);
        
        QJsonObject nameObj;
        nameObj["value"] = query.value(5).toString();
        nameObj["rowNumber"] = query.value(0).toInt();
        nameObj["pageNumber"] = 1;
        nameObj["isHeader"] = nameCellObj["isHeader"].toBool(query.value(8).toBool());
        nameObj["isAutoGenerated"] = query.value(14).toBool();
        nameObj["isEmpty"] = query.value(5).toString().isEmpty();
        nameObj["stretch"] = nameCellObj["stretch"].toInt(100);
        nameObj["isUnderline"] = nameCellObj["isUnderline"].toBool(false);
        
        QJsonObject quantityObj;
        quantityObj["value"] = query.value(6).toString();
        quantityObj["rowNumber"] = query.value(0).toInt();
        quantityObj["pageNumber"] = 1;
        quantityObj["isHeader"] = quantityCellObj["isHeader"].toBool(query.value(8).toBool());
        quantityObj["isAutoGenerated"] = query.value(15).toBool();
        quantityObj["isEmpty"] = query.value(6).toString().isEmpty();
        quantityObj["stretch"] = quantityCellObj["stretch"].toInt(100);
        quantityObj["isUnderline"] = quantityCellObj["isUnderline"].toBool(false);
        
        QJsonObject noteObj;
        noteObj["value"] = query.value(7).toString();
        noteObj["rowNumber"] = query.value(0).toInt();
        noteObj["pageNumber"] = 1;
        noteObj["isHeader"] = noteCellObj["isHeader"].toBool(query.value(8).toBool());
        noteObj["isAutoGenerated"] = query.value(16).toBool();
        noteObj["isEmpty"] = query.value(7).toString().isEmpty();
        noteObj["stretch"] = noteCellObj["stretch"].toInt(100);
        noteObj["isUnderline"] = noteCellObj["isUnderline"].toBool(false);
        
        // Создаем объект строки
        rowObj["format"] = formatObj;
        rowObj["zone"] = zoneObj;
        rowObj["position"] = positionObj;
        rowObj["designation"] = designationObj;
        rowObj["name"] = nameObj;
        rowObj["quantity"] = quantityObj;
        rowObj["note"] = noteObj;
        rowObj["isHeader"] = query.value(8).toBool();
        rowObj["isEmpty"] = query.value(9).toBool();
        rowObj["rowNumber"] = query.value(0).toInt();
        rowObj["pageNumber"] = 1;
        
        rowsArray.append(rowObj);
    }
    
    root["rows"] = rowsArray;
    root["columnMappings"] = QJsonArray::fromStringList(QStringList() << "Format" << "Zone" << "Position" << "Designator" << "Name" << "Quantity" << "Note");
    root["propertyNames"] = QJsonArray::fromStringList(QStringList() << "Designator" << "Format" << "Zone" << "Position");
    
    QJsonDocument doc(root);
    QByteArray result = doc.toJson();
    
    qDebug() << "DataBaseController::loadSpecificationPCBTable: Загружено" << rowsArray.size() << "строк";
    return result;
}

bool DataBaseController::deleteSpecificationPCBTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    QSqlQuery query = prepareQuery("DELETE FROM specification_pcb_rows WHERE project_name = ?");
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления спецификации платы: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QStringList DataBaseController::getAvailableSpecificationPCBProjects()
{
    QStringList projects;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return projects;
    }
    
    QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM specification_pcb_rows ORDER BY project_name");
    
    if (!query.exec()) {
        setLastError("Ошибка получения списка проектов спецификации платы: " + query.lastError().text());
        return projects;
    }
    
    while (query.next()) {
        projects << query.value(0).toString();
    }
    
    return projects;
}

QString DataBaseController::getSpecificationPCBTableInfo(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QString();
    }
    
    QString actualProjectName = projectName;
    if (actualProjectName.isEmpty()) {
        actualProjectName = QFileInfo(m_database.databaseName()).baseName();
    }
    
    QSqlQuery query = prepareQuery(
        "SELECT row_order, format_value, zone_value, position_value, designation_value, name_value, quantity_value, note_value, "
        "is_header, is_empty, format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto "
        "FROM specification_pcb_rows WHERE project_name = ? ORDER BY row_order"
    );
    query.addBindValue(actualProjectName);
    
    if (!query.exec()) {
        setLastError("Ошибка получения информации о спецификации платы: " + query.lastError().text());
        return QString();
    }
    
    QString info = QString("Информация о спецификации платы для проекта '%1':\n").arg(actualProjectName);
    info += QString("Всего строк: %1\n\n").arg(query.size());
    
    while (query.next()) {
        int rowOrder = query.value(0).toInt();
        QString format = query.value(1).toString();
        QString zone = query.value(2).toString();
        QString position = query.value(3).toString();
        QString designation = query.value(4).toString();
        QString name = query.value(5).toString();
        QString quantity = query.value(6).toString();
        QString note = query.value(7).toString();
        bool isHeader = query.value(8).toBool();
        bool isEmpty = query.value(9).toBool();
        bool formatAuto = query.value(10).toBool();
        bool zoneAuto = query.value(11).toBool();
        bool posAuto = query.value(12).toBool();
        bool desAuto = query.value(13).toBool();
        bool nameAuto = query.value(14).toBool();
        bool qtyAuto = query.value(15).toBool();
        bool noteAuto = query.value(16).toBool();
        
        info += QString("Строка %1:\n").arg(rowOrder);
        info += QString("  Формат: '%1' (авто: %2)\n").arg(format).arg(formatAuto ? "да" : "нет");
        info += QString("  Зона: '%1' (авто: %2)\n").arg(zone).arg(zoneAuto ? "да" : "нет");
        info += QString("  Поз.: '%1' (авто: %2)\n").arg(position).arg(posAuto ? "да" : "нет");
        info += QString("  Обозн.: '%1' (авто: %2)\n").arg(designation).arg(desAuto ? "да" : "нет");
        info += QString("  Наим.: '%1' (авто: %2)\n").arg(name).arg(nameAuto ? "да" : "нет");
        info += QString("  Кол.: '%1' (авто: %2)\n").arg(quantity).arg(qtyAuto ? "да" : "нет");
        info += QString("  Прим.: '%1' (авто: %2)\n").arg(note).arg(noteAuto ? "да" : "нет");
        info += QString("  Заголовок: %1, Пустая: %2\n\n").arg(isHeader ? "да" : "нет").arg(isEmpty ? "да" : "нет");
    }
    
    return info;
}

// Работа со спецификацией материалов
bool DataBaseController::saveSpecificationTable(const QByteArray &tableData, const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    qDebug() << "DataBaseController::saveSpecificationTable: Сохраняем спецификацию для проекта:" << projectName;
    
    // Начинаем транзакцию
    if (!beginTransaction()) {
        return false;
    }
    
    // Удаляем существующие записи для данного проекта
    QSqlQuery deleteQuery = prepareQuery("DELETE FROM specification_rows WHERE project_name = ?");
    deleteQuery.addBindValue(projectName);
    if (!deleteQuery.exec()) {
        setLastError("Ошибка удаления существующей спецификации: " + deleteQuery.lastError().text());
        qDebug() << "DataBaseController::saveSpecificationTable: Ошибка удаления:" << deleteQuery.lastError().text();
        rollbackTransaction();
        return false;
    }
    
    // Парсим JSON данные и сохраняем каждую строку отдельно
    QJsonDocument doc = QJsonDocument::fromJson(tableData);
    if (!doc.isObject()) {
        setLastError("Ошибка парсинга JSON данных спецификации");
        rollbackTransaction();
        return false;
    }
    
    QJsonObject root = doc.object();
    QJsonArray rowsArray = root["rows"].toArray();
    
    int rowOrder = 0;
    for (const QJsonValue &value : rowsArray) {
        QJsonObject rowObj = value.toObject();
        
        // Получаем данные ячеек для 7 столбцов
        QJsonObject formatObj = rowObj["format"].toObject();
        QJsonObject zoneObj = rowObj["zone"].toObject();
        QJsonObject positionObj = rowObj["position"].toObject();
        QJsonObject designationObj = rowObj["designation"].toObject();
        QJsonObject nameObj = rowObj["name"].toObject();
        QJsonObject quantityObj = rowObj["quantity"].toObject();
        QJsonObject noteObj = rowObj["note"].toObject();
        
        // Формируем JSON объект с настройками ячеек (stretch, isHeader, isUnderline)
        QJsonObject cellSettingsObj;
        
        QJsonObject formatCellObj;
        formatCellObj["stretch"] = formatObj["stretch"].toInt(100);
        formatCellObj["isHeader"] = formatObj["isHeader"].toBool(false);
        formatCellObj["isUnderline"] = formatObj["isUnderline"].toBool(false);
        cellSettingsObj["format"] = formatCellObj;
        
        QJsonObject zoneCellObj;
        zoneCellObj["stretch"] = zoneObj["stretch"].toInt(100);
        zoneCellObj["isHeader"] = zoneObj["isHeader"].toBool(false);
        zoneCellObj["isUnderline"] = zoneObj["isUnderline"].toBool(false);
        cellSettingsObj["zone"] = zoneCellObj;
        
        QJsonObject positionCellObj;
        positionCellObj["stretch"] = positionObj["stretch"].toInt(100);
        positionCellObj["isHeader"] = positionObj["isHeader"].toBool(false);
        positionCellObj["isUnderline"] = positionObj["isUnderline"].toBool(false);
        cellSettingsObj["position"] = positionCellObj;
        
        QJsonObject designationCellObj;
        designationCellObj["stretch"] = designationObj["stretch"].toInt(100);
        designationCellObj["isHeader"] = designationObj["isHeader"].toBool(false);
        designationCellObj["isUnderline"] = designationObj["isUnderline"].toBool(false);
        cellSettingsObj["designation"] = designationCellObj;
        
        QJsonObject nameCellObj;
        nameCellObj["stretch"] = nameObj["stretch"].toInt(100);
        nameCellObj["isHeader"] = nameObj["isHeader"].toBool(false);
        nameCellObj["isUnderline"] = nameObj["isUnderline"].toBool(false);
        cellSettingsObj["name"] = nameCellObj;
        
        QJsonObject quantityCellObj;
        quantityCellObj["stretch"] = quantityObj["stretch"].toInt(100);
        quantityCellObj["isHeader"] = quantityObj["isHeader"].toBool(false);
        quantityCellObj["isUnderline"] = quantityObj["isUnderline"].toBool(false);
        cellSettingsObj["quantity"] = quantityCellObj;
        
        QJsonObject noteCellObj;
        noteCellObj["stretch"] = noteObj["stretch"].toInt(100);
        noteCellObj["isHeader"] = noteObj["isHeader"].toBool(false);
        noteCellObj["isUnderline"] = noteObj["isUnderline"].toBool(false);
        cellSettingsObj["note"] = noteCellObj;
        
        QJsonDocument cellSettingsDoc(cellSettingsObj);
        QString cellSettingsJson = cellSettingsDoc.toJson(QJsonDocument::Compact);
        
        // Добавляем строку в БД
        QSqlQuery insertQuery = prepareQuery(
            "INSERT INTO specification_rows (project_name, row_order, format_value, zone_value, position_value, "
            "designation_value, name_value, quantity_value, note_value, is_header, is_empty, "
            "format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto, cell_stretches) "
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
        );
        
        insertQuery.addBindValue(projectName);
        insertQuery.addBindValue(rowOrder++);
        insertQuery.addBindValue(formatObj["value"].toString());
        insertQuery.addBindValue(zoneObj["value"].toString());
        insertQuery.addBindValue(positionObj["value"].toString());
        insertQuery.addBindValue(designationObj["value"].toString());
        insertQuery.addBindValue(nameObj["value"].toString());
        insertQuery.addBindValue(quantityObj["value"].toString());
        insertQuery.addBindValue(noteObj["value"].toString());
        insertQuery.addBindValue(rowObj["isHeader"].toBool());
        insertQuery.addBindValue(rowObj["isEmpty"].toBool());
        insertQuery.addBindValue(formatObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(zoneObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(positionObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(designationObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(nameObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(quantityObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(noteObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(cellSettingsJson);
        
        if (!insertQuery.exec()) {
            setLastError("Ошибка сохранения строки спецификации: " + insertQuery.lastError().text());
            qDebug() << "DataBaseController::saveSpecificationTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text();
            rollbackTransaction();
            return false;
        }
    }
    
    // Подтверждаем транзакцию
    if (!commitTransaction()) {
        return false;
    }
    
    qDebug() << "DataBaseController::saveSpecificationTable: Спецификация успешно сохранена," << rowsArray.size() << "строк";
    emit dataChanged();
    return true;
}

QByteArray DataBaseController::loadSpecificationTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QByteArray();
    }
    
    qDebug() << "DataBaseController::loadSpecificationTable: Загружаем спецификацию для проекта:" << projectName;
    
    QSqlQuery query = prepareQuery(
        "SELECT row_order, format_value, zone_value, position_value, designation_value, name_value, quantity_value, note_value, "
        "is_header, is_empty, format_is_auto, zone_is_auto, position_is_auto, designation_is_auto, name_is_auto, quantity_is_auto, note_is_auto, cell_stretches "
        "FROM specification_rows WHERE project_name = ? ORDER BY row_order"
    );
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка загрузки спецификации: " + query.lastError().text());
        qDebug() << "DataBaseController::loadSpecificationTable: Ошибка выполнения запроса:" << query.lastError().text();
        return QByteArray();
    }
    
    // Создаем JSON структуру для совместимости с SpecificationTableModel
    QJsonObject root;
    QJsonArray rowsArray;
    
    while (query.next()) {
        QJsonObject rowObj;
        
        // Загружаем настройки ячеек (stretch, isHeader, isUnderline) из JSON
        QJsonObject cellSettingsObj;
        QString cellSettingsJson = query.value(17).toString();
        if (!cellSettingsJson.isEmpty()) {
            QJsonDocument cellSettingsDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8());
            if (cellSettingsDoc.isObject()) {
                cellSettingsObj = cellSettingsDoc.object();
            }
        }
        
        // Получаем настройки для каждой ячейки
        QJsonObject formatCellObj = cellSettingsObj["format"].toObject();
        QJsonObject zoneCellObj = cellSettingsObj["zone"].toObject();
        QJsonObject positionCellObj = cellSettingsObj["position"].toObject();
        QJsonObject designationCellObj = cellSettingsObj["designation"].toObject();
        QJsonObject nameCellObj = cellSettingsObj["name"].toObject();
        QJsonObject quantityCellObj = cellSettingsObj["quantity"].toObject();
        QJsonObject noteCellObj = cellSettingsObj["note"].toObject();
        
        // Создаем объекты для каждой ячейки (7 столбцов)
        QJsonObject formatObj;
        formatObj["value"] = query.value(1).toString();
        formatObj["rowNumber"] = query.value(0).toInt();
        formatObj["pageNumber"] = 1;
        formatObj["isHeader"] = formatCellObj["isHeader"].toBool(query.value(8).toBool());
        formatObj["isAutoGenerated"] = query.value(10).toBool();
        formatObj["isEmpty"] = query.value(1).toString().isEmpty();
        formatObj["stretch"] = formatCellObj["stretch"].toInt(100);
        formatObj["isUnderline"] = formatCellObj["isUnderline"].toBool(false);
        
        QJsonObject zoneObj;
        zoneObj["value"] = query.value(2).toString();
        zoneObj["rowNumber"] = query.value(0).toInt();
        zoneObj["pageNumber"] = 1;
        zoneObj["isHeader"] = zoneCellObj["isHeader"].toBool(query.value(8).toBool());
        zoneObj["isAutoGenerated"] = query.value(11).toBool();
        zoneObj["isEmpty"] = query.value(2).toString().isEmpty();
        zoneObj["stretch"] = zoneCellObj["stretch"].toInt(100);
        zoneObj["isUnderline"] = zoneCellObj["isUnderline"].toBool(false);
        
        QJsonObject positionObj;
        positionObj["value"] = query.value(3).toString();
        positionObj["rowNumber"] = query.value(0).toInt();
        positionObj["pageNumber"] = 1;
        positionObj["isHeader"] = positionCellObj["isHeader"].toBool(query.value(8).toBool());
        positionObj["isAutoGenerated"] = query.value(12).toBool();
        positionObj["isEmpty"] = query.value(3).toString().isEmpty();
        positionObj["stretch"] = positionCellObj["stretch"].toInt(100);
        positionObj["isUnderline"] = positionCellObj["isUnderline"].toBool(false);
        
        QJsonObject designationObj;
        designationObj["value"] = query.value(4).toString();
        designationObj["rowNumber"] = query.value(0).toInt();
        designationObj["pageNumber"] = 1;
        designationObj["isHeader"] = designationCellObj["isHeader"].toBool(query.value(8).toBool());
        designationObj["isAutoGenerated"] = query.value(13).toBool();
        designationObj["isEmpty"] = query.value(4).toString().isEmpty();
        designationObj["stretch"] = designationCellObj["stretch"].toInt(100);
        designationObj["isUnderline"] = designationCellObj["isUnderline"].toBool(false);
        
        QJsonObject nameObj;
        nameObj["value"] = query.value(5).toString();
        nameObj["rowNumber"] = query.value(0).toInt();
        nameObj["pageNumber"] = 1;
        nameObj["isHeader"] = nameCellObj["isHeader"].toBool(query.value(8).toBool());
        nameObj["isAutoGenerated"] = query.value(14).toBool();
        nameObj["isEmpty"] = query.value(5).toString().isEmpty();
        nameObj["stretch"] = nameCellObj["stretch"].toInt(100);
        nameObj["isUnderline"] = nameCellObj["isUnderline"].toBool(false);
        
        QJsonObject quantityObj;
        quantityObj["value"] = query.value(6).toString();
        quantityObj["rowNumber"] = query.value(0).toInt();
        quantityObj["pageNumber"] = 1;
        quantityObj["isHeader"] = quantityCellObj["isHeader"].toBool(query.value(8).toBool());
        quantityObj["isAutoGenerated"] = query.value(15).toBool();
        quantityObj["isEmpty"] = query.value(6).toString().isEmpty();
        quantityObj["stretch"] = quantityCellObj["stretch"].toInt(100);
        quantityObj["isUnderline"] = quantityCellObj["isUnderline"].toBool(false);
        
        QJsonObject noteObj;
        noteObj["value"] = query.value(7).toString();
        noteObj["rowNumber"] = query.value(0).toInt();
        noteObj["pageNumber"] = 1;
        noteObj["isHeader"] = noteCellObj["isHeader"].toBool(query.value(8).toBool());
        noteObj["isAutoGenerated"] = query.value(16).toBool();
        noteObj["isEmpty"] = query.value(7).toString().isEmpty();
        noteObj["stretch"] = noteCellObj["stretch"].toInt(100);
        noteObj["isUnderline"] = noteCellObj["isUnderline"].toBool(false);
        
        // Создаем объект строки
        rowObj["format"] = formatObj;
        rowObj["zone"] = zoneObj;
        rowObj["position"] = positionObj;
        rowObj["designation"] = designationObj;
        rowObj["name"] = nameObj;
        rowObj["quantity"] = quantityObj;
        rowObj["note"] = noteObj;
        rowObj["isHeader"] = query.value(8).toBool();
        rowObj["isEmpty"] = query.value(9).toBool();
        rowObj["rowNumber"] = query.value(0).toInt();
        rowObj["pageNumber"] = 1;
        
        rowsArray.append(rowObj);
    }
    
    root["rows"] = rowsArray;
    root["columnMappings"] = QJsonArray::fromStringList(QStringList() << "Format" << "Zone" << "Position" << "Designation" << "Name" << "Quantity" << "Note");
    root["propertyNames"] = QJsonArray::fromStringList(QStringList() << "Name" << "Value" << "Height" << "DielType" << "LayerNumber");
    
    QJsonDocument doc(root);
    QByteArray result = doc.toJson();
    
    qDebug() << "DataBaseController::loadSpecificationTable: Загружено" << rowsArray.size() << "строк";
    return result;
}

bool DataBaseController::deleteSpecificationTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    QSqlQuery query = prepareQuery("DELETE FROM specification_rows WHERE project_name = ?");
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления спецификации: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

QStringList DataBaseController::getAvailableSpecificationProjects()
{
    QStringList projects;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return projects;
    }
    
    QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM specification_rows ORDER BY project_name");
    
    if (!query.exec()) {
        setLastError("Ошибка получения списка проектов спецификации: " + query.lastError().text());
        return projects;
    }
    
    while (query.next()) {
        projects << query.value(0).toString();
    }
    
    return projects;
}

QString DataBaseController::getSpecificationTableInfo(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QString();
    }
    
    qDebug() << "DataBaseController::getSpecificationTableInfo: Получаем информацию о спецификации материалов для проекта:" << projectName;
    
    QSqlQuery query = prepareQuery(
        "SELECT COUNT(*) as total_rows, "
        "SUM(CASE WHEN is_header = 1 THEN 1 ELSE 0 END) as header_rows, "
        "SUM(CASE WHEN is_empty = 1 THEN 1 ELSE 0 END) as empty_rows, "
        "MIN(row_order) as min_order, "
        "MAX(row_order) as max_order "
        "FROM specification_rows WHERE project_name = ?"
    );
    query.addBindValue(projectName);
    
    if (!query.exec() || !query.next()) {
        setLastError("Ошибка получения информации о спецификации: " + query.lastError().text());
        return QString();
    }
    
    int totalRows = query.value(0).toInt();
    int headerRows = query.value(1).toInt();
    int emptyRows = query.value(2).toInt();
    int minOrder = query.value(3).toInt();
    int maxOrder = query.value(4).toInt();
    
    QString info = QString("Спецификация для проекта '%1':\n"
                          "Всего строк: %2\n"
                          "Заголовков: %3\n"
                          "Пустых строк: %4\n"
                          "Диапазон строк: %5-%6")
                          .arg(projectName)
                          .arg(totalRows)
                          .arg(headerRows)
                          .arg(emptyRows)
                          .arg(minOrder)
                          .arg(maxOrder);
    
    qDebug() << "DataBaseController::getSpecificationTableInfo: Информация получена:" << info;
    return info;
}

// Работа с ведомостью покупных изделий
bool DataBaseController::saveVedomostTable(const QByteArray &tableData, const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    qDebug() << "DataBaseController::saveVedomostTable: Сохраняем ведомость покупных изделий для проекта:" << projectName;
    
    // Начинаем транзакцию
    if (!beginTransaction()) {
        return false;
    }
    
    // Удаляем существующие данные для этого проекта
    QSqlQuery deleteQuery = prepareQuery("DELETE FROM vedomost_rows WHERE project_name = ?");
    deleteQuery.addBindValue(projectName);
    
    if (!deleteQuery.exec()) {
        qDebug() << "DataBaseController::saveVedomostTable: Ошибка удаления:" << deleteQuery.lastError().text();
        setLastError("Ошибка удаления существующих данных ведомости: " + deleteQuery.lastError().text());
        rollbackTransaction();
        return false;
    }
    
    // Парсим JSON данные и сохраняем каждую строку отдельно
    QJsonDocument doc = QJsonDocument::fromJson(tableData);
    if (!doc.isObject()) {
        setLastError("Ошибка парсинга JSON данных ведомости");
        rollbackTransaction();
        return false;
    }
    
    QJsonObject root = doc.object();
    QJsonArray rowsArray = root["rows"].toArray();
    
    int rowOrder = 0;
    for (const QJsonValue &value : rowsArray) {
        QJsonObject rowObj = value.toObject();
        
        // Отладочная информация для первых нескольких строк
        if (rowOrder < 5) {
            qDebug() << "DataBaseController::saveVedomostTable: Обрабатываем строку" << rowOrder << ":";
            if (rowObj.contains("name")) {
                QJsonObject nameObj = rowObj["name"].toObject();
                qDebug() << "  name.value:" << nameObj["value"].toString();
            }
            if (rowObj.contains("productCode")) {
                QJsonObject productCodeObj = rowObj["productCode"].toObject();
                qDebug() << "  productCode.value:" << productCodeObj["value"].toString();
            }
            qDebug() << "  isHeader:" << rowObj["isHeader"].toBool();
            qDebug() << "  isEmpty:" << rowObj["isEmpty"].toBool();
        }
        
        // Получаем данные ячеек
        QJsonObject nameObj = rowObj["name"].toObject();
        QJsonObject productCodeObj = rowObj["productCode"].toObject();
        QJsonObject documentCodeObj = rowObj["documentCode"].toObject();
        QJsonObject supplierObj = rowObj["supplier"].toObject();
        QJsonObject whereUsedObj = rowObj["whereUsed"].toObject();
        QJsonObject quantityPerItemObj = rowObj["quantityPerItem"].toObject();
        QJsonObject quantityInSetObj = rowObj["quantityInSet"].toObject();
        QJsonObject quantityForRegObj = rowObj["quantityForReg"].toObject();
        QJsonObject totalQuantityObj = rowObj["totalQuantity"].toObject();
        QJsonObject noteObj = rowObj["note"].toObject();
        
        // Формируем JSON объект с настройками ячеек (stretch, isHeader, isUnderline)
        QJsonObject cellSettingsObj;
        
        QJsonObject nameCellObj;
        nameCellObj["stretch"] = nameObj["stretch"].toInt(100);
        nameCellObj["isHeader"] = nameObj["isHeader"].toBool(false);
        nameCellObj["isUnderline"] = nameObj["isUnderline"].toBool(false);
        cellSettingsObj["name"] = nameCellObj;
        
        QJsonObject productCodeCellObj;
        productCodeCellObj["stretch"] = productCodeObj["stretch"].toInt(100);
        productCodeCellObj["isHeader"] = productCodeObj["isHeader"].toBool(false);
        productCodeCellObj["isUnderline"] = productCodeObj["isUnderline"].toBool(false);
        cellSettingsObj["productCode"] = productCodeCellObj;
        
        QJsonObject documentCodeCellObj;
        documentCodeCellObj["stretch"] = documentCodeObj["stretch"].toInt(100);
        documentCodeCellObj["isHeader"] = documentCodeObj["isHeader"].toBool(false);
        documentCodeCellObj["isUnderline"] = documentCodeObj["isUnderline"].toBool(false);
        cellSettingsObj["documentCode"] = documentCodeCellObj;
        
        QJsonObject supplierCellObj;
        supplierCellObj["stretch"] = supplierObj["stretch"].toInt(100);
        supplierCellObj["isHeader"] = supplierObj["isHeader"].toBool(false);
        supplierCellObj["isUnderline"] = supplierObj["isUnderline"].toBool(false);
        cellSettingsObj["supplier"] = supplierCellObj;
        
        QJsonObject whereUsedCellObj;
        whereUsedCellObj["stretch"] = whereUsedObj["stretch"].toInt(100);
        whereUsedCellObj["isHeader"] = whereUsedObj["isHeader"].toBool(false);
        whereUsedCellObj["isUnderline"] = whereUsedObj["isUnderline"].toBool(false);
        cellSettingsObj["whereUsed"] = whereUsedCellObj;
        
        QJsonObject quantityPerItemCellObj;
        quantityPerItemCellObj["stretch"] = quantityPerItemObj["stretch"].toInt(100);
        quantityPerItemCellObj["isHeader"] = quantityPerItemObj["isHeader"].toBool(false);
        quantityPerItemCellObj["isUnderline"] = quantityPerItemObj["isUnderline"].toBool(false);
        cellSettingsObj["quantityPerItem"] = quantityPerItemCellObj;
        
        QJsonObject quantityInSetCellObj;
        quantityInSetCellObj["stretch"] = quantityInSetObj["stretch"].toInt(100);
        quantityInSetCellObj["isHeader"] = quantityInSetObj["isHeader"].toBool(false);
        quantityInSetCellObj["isUnderline"] = quantityInSetObj["isUnderline"].toBool(false);
        cellSettingsObj["quantityInSet"] = quantityInSetCellObj;
        
        QJsonObject quantityForRegCellObj;
        quantityForRegCellObj["stretch"] = quantityForRegObj["stretch"].toInt(100);
        quantityForRegCellObj["isHeader"] = quantityForRegObj["isHeader"].toBool(false);
        quantityForRegCellObj["isUnderline"] = quantityForRegObj["isUnderline"].toBool(false);
        cellSettingsObj["quantityForReg"] = quantityForRegCellObj;
        
        QJsonObject totalQuantityCellObj;
        totalQuantityCellObj["stretch"] = totalQuantityObj["stretch"].toInt(100);
        totalQuantityCellObj["isHeader"] = totalQuantityObj["isHeader"].toBool(false);
        totalQuantityCellObj["isUnderline"] = totalQuantityObj["isUnderline"].toBool(false);
        cellSettingsObj["totalQuantity"] = totalQuantityCellObj;
        
        QJsonObject noteCellObj;
        noteCellObj["stretch"] = noteObj["stretch"].toInt(100);
        noteCellObj["isHeader"] = noteObj["isHeader"].toBool(false);
        noteCellObj["isUnderline"] = noteObj["isUnderline"].toBool(false);
        cellSettingsObj["note"] = noteCellObj;
        
        QJsonDocument cellSettingsDoc(cellSettingsObj);
        QString cellSettingsJson = cellSettingsDoc.toJson(QJsonDocument::Compact);
        
        // Добавляем строку в БД
    QSqlQuery insertQuery = prepareQuery(
        "INSERT INTO vedomost_rows (project_name, row_order, name_value, product_code_value, document_code_value, "
        "supplier_value, where_used_value, quantity_per_item_value, quantity_in_set_value, quantity_for_reg_value, total_quantity_value, "
        "note_value, is_header, is_empty, row_number, page_number, cell_stretches) "
        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
    );
        
        insertQuery.addBindValue(projectName);
        insertQuery.addBindValue(rowOrder++);
        insertQuery.addBindValue(nameObj["value"].toString());
        insertQuery.addBindValue(productCodeObj["value"].toString());
        insertQuery.addBindValue(documentCodeObj["value"].toString());
        insertQuery.addBindValue(supplierObj["value"].toString());
        insertQuery.addBindValue(whereUsedObj["value"].toString());
        insertQuery.addBindValue(quantityPerItemObj["value"].toString());
        insertQuery.addBindValue(quantityInSetObj["value"].toString());
        insertQuery.addBindValue(quantityForRegObj["value"].toString());
        insertQuery.addBindValue(totalQuantityObj["value"].toString());
        insertQuery.addBindValue(noteObj["value"].toString());
        insertQuery.addBindValue(rowObj["isHeader"].toBool());
        insertQuery.addBindValue(rowObj["isEmpty"].toBool());
        insertQuery.addBindValue(rowObj["rowNumber"].toInt());
        insertQuery.addBindValue(rowObj["pageNumber"].toInt());
        insertQuery.addBindValue(cellSettingsJson);
        
        if (!insertQuery.exec()) {
            qDebug() << "DataBaseController::saveVedomostTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text();
            setLastError("Ошибка сохранения строки ведомости: " + insertQuery.lastError().text());
            rollbackTransaction();
            return false;
        }
    }
    
    // Подтверждаем транзакцию
    if (!commitTransaction()) {
        return false;
    }
    
    qDebug() << "DataBaseController::saveVedomostTable: Ведомость успешно сохранена," << rowsArray.size() << "строк";
    emit dataChanged();
    return true;
}

// Работа с бланком заказа
bool DataBaseController::saveSimpleListTable(const QByteArray &tableData, const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    qDebug() << "DataBaseController::saveSimpleListTable: Сохраняем бланк заказа для проекта:" << projectName;
    
    // Начинаем транзакцию
    if (!beginTransaction()) {
        return false;
    }
    
    // Удаляем существующие данные для этого проекта
    QSqlQuery deleteQuery = prepareQuery("DELETE FROM simple_list_rows WHERE project_name = ?");
    deleteQuery.addBindValue(projectName);
    
    if (!deleteQuery.exec()) {
        qDebug() << "DataBaseController::saveSimpleListTable: Ошибка удаления:" << deleteQuery.lastError().text();
        setLastError("Ошибка удаления существующих данных бланка заказа: " + deleteQuery.lastError().text());
        rollbackTransaction();
        return false;
    }
    
    // Парсим JSON данные и сохраняем каждую строку отдельно
    QJsonDocument doc = QJsonDocument::fromJson(tableData);
    if (!doc.isObject()) {
        setLastError("Ошибка парсинга JSON данных бланка заказа");
        rollbackTransaction();
        return false;
    }
    
    QJsonObject root = doc.object();
    QJsonArray rowsArray = root["rows"].toArray();
    
    int rowOrder = 0;
    for (const QJsonValue &value : rowsArray) {
        QJsonObject rowObj = value.toObject();
        
        // Получаем данные ячеек
        QJsonObject designatorObj = rowObj["designator"].toObject();
        QJsonObject nameObj = rowObj["name"].toObject();
        QJsonObject quantityObj = rowObj["quantity"].toObject();
        
        // Добавляем строку в БД
        QSqlQuery insertQuery = prepareQuery(
            "INSERT INTO simple_list_rows (project_name, row_order, designator_value, name_value, quantity_value, "
            "is_empty, designator_is_auto, name_is_auto, quantity_is_auto) "
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
        );
        
        insertQuery.addBindValue(projectName);
        insertQuery.addBindValue(rowOrder++);
        insertQuery.addBindValue(designatorObj["value"].toString());
        insertQuery.addBindValue(nameObj["value"].toString());
        insertQuery.addBindValue(quantityObj["value"].toString());
        insertQuery.addBindValue(rowObj["isEmpty"].toBool());
        insertQuery.addBindValue(designatorObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(nameObj["isAutoGenerated"].toBool());
        insertQuery.addBindValue(quantityObj["isAutoGenerated"].toBool());
        
        if (!insertQuery.exec()) {
            qDebug() << "DataBaseController::saveSimpleListTable: Ошибка сохранения строки" << rowOrder-1 << ":" << insertQuery.lastError().text();
            setLastError("Ошибка сохранения строки бланка заказа: " + insertQuery.lastError().text());
            rollbackTransaction();
            return false;
        }
    }
    
    // Подтверждаем транзакцию
    if (!commitTransaction()) {
        return false;
    }
    
    qDebug() << "DataBaseController::saveSimpleListTable: Бланк заказа успешно сохранен," << rowsArray.size() << "строк";
    emit dataChanged();
    return true;
}

QByteArray DataBaseController::loadSimpleListTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QByteArray();
    }
    
    qDebug() << "DataBaseController::loadSimpleListTable: Загружаем бланк заказа для проекта:" << projectName;
    
    QSqlQuery query = prepareQuery(
        "SELECT designator_value, name_value, quantity_value, is_empty, designator_is_auto, name_is_auto, quantity_is_auto "
        "FROM simple_list_rows WHERE project_name = ? ORDER BY row_order"
    );
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка загрузки бланка заказа: " + query.lastError().text());
        return QByteArray();
    }
    
    QJsonObject root;
    QJsonArray rowsArray;
    
    while (query.next()) {
        QJsonObject rowObj;
        
        // Получаем данные ячеек
        QJsonObject designatorObj;
        designatorObj["value"] = query.value(0).toString();
        designatorObj["isAutoGenerated"] = query.value(4).toBool();
        designatorObj["isEmpty"] = false;
        rowObj["designator"] = designatorObj;
        
        QJsonObject nameObj;
        nameObj["value"] = query.value(1).toString();
        nameObj["isAutoGenerated"] = query.value(5).toBool();
        nameObj["isEmpty"] = false;
        rowObj["name"] = nameObj;
        
        QJsonObject quantityObj;
        quantityObj["value"] = query.value(2).toString();
        quantityObj["isAutoGenerated"] = query.value(6).toBool();
        quantityObj["isEmpty"] = false;
        rowObj["quantity"] = quantityObj;
        
        rowObj["isEmpty"] = query.value(3).toBool();
        
        rowsArray.append(rowObj);
    }
    
    root["rows"] = rowsArray;
    
    QJsonDocument doc(root);
    QByteArray result = doc.toJson();
    
    qDebug() << "DataBaseController::loadSimpleListTable: Загружено" << rowsArray.size() << "строк";
    return result;
}

QByteArray DataBaseController::loadVedomostTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QByteArray();
    }
    
    qDebug() << "DataBaseController::loadVedomostTable: Загружаем ведомость покупных изделий для проекта:" << projectName;
    
    QSqlQuery query = prepareQuery(
        "SELECT name_value, product_code_value, document_code_value, supplier_value, where_used_value, quantity_per_item_value, "
        "quantity_in_set_value, quantity_for_reg_value, total_quantity_value, note_value, is_header, is_empty, row_number, page_number, cell_stretches "
        "FROM vedomost_rows WHERE project_name = ? ORDER BY row_order"
    );
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка загрузки ведомости покупных изделий: " + query.lastError().text());
        return QByteArray();
    }
    
    QJsonObject root;
    QJsonArray rowsArray;
    
    while (query.next()) {
        QJsonObject rowObj;
        
        // Загружаем настройки ячеек (stretch, isHeader, isUnderline) из JSON
        QJsonObject cellSettingsObj;
        QString cellSettingsJson = query.value(14).toString();
        if (!cellSettingsJson.isEmpty()) {
            QJsonDocument cellSettingsDoc = QJsonDocument::fromJson(cellSettingsJson.toUtf8());
            if (cellSettingsDoc.isObject()) {
                cellSettingsObj = cellSettingsDoc.object();
            }
        }
        
        // Получаем настройки для каждой ячейки
        QJsonObject nameCellObj = cellSettingsObj["name"].toObject();
        QJsonObject productCodeCellObj = cellSettingsObj["productCode"].toObject();
        QJsonObject documentCodeCellObj = cellSettingsObj["documentCode"].toObject();
        QJsonObject supplierCellObj = cellSettingsObj["supplier"].toObject();
        QJsonObject whereUsedCellObj = cellSettingsObj["whereUsed"].toObject();
        QJsonObject quantityPerItemCellObj = cellSettingsObj["quantityPerItem"].toObject();
        QJsonObject quantityInSetCellObj = cellSettingsObj["quantityInSet"].toObject();
        QJsonObject quantityForRegCellObj = cellSettingsObj["quantityForReg"].toObject();
        QJsonObject totalQuantityCellObj = cellSettingsObj["totalQuantity"].toObject();
        QJsonObject noteCellObj = cellSettingsObj["note"].toObject();
        
        // Создаем объекты для каждой ячейки
        QJsonObject nameObj;
        nameObj["value"] = query.value(0).toString();
        nameObj["rowNumber"] = query.value(12).toInt();
        nameObj["pageNumber"] = query.value(13).toInt();
        nameObj["isHeader"] = nameCellObj["isHeader"].toBool(query.value(10).toBool());
        nameObj["isAutoGenerated"] = false;
        nameObj["isEmpty"] = query.value(11).toBool();
        nameObj["stretch"] = nameCellObj["stretch"].toInt(100);
        nameObj["isUnderline"] = nameCellObj["isUnderline"].toBool(false);
        rowObj["name"] = nameObj;
        
        QJsonObject productCodeObj;
        productCodeObj["value"] = query.value(1).toString();
        productCodeObj["rowNumber"] = query.value(12).toInt();
        productCodeObj["pageNumber"] = query.value(13).toInt();
        productCodeObj["isHeader"] = productCodeCellObj["isHeader"].toBool(query.value(10).toBool());
        productCodeObj["isAutoGenerated"] = false;
        productCodeObj["isEmpty"] = query.value(11).toBool();
        productCodeObj["stretch"] = productCodeCellObj["stretch"].toInt(100);
        productCodeObj["isUnderline"] = productCodeCellObj["isUnderline"].toBool(false);
        rowObj["productCode"] = productCodeObj;
        
        QJsonObject documentCodeObj;
        documentCodeObj["value"] = query.value(2).toString();
        documentCodeObj["rowNumber"] = query.value(12).toInt();
        documentCodeObj["pageNumber"] = query.value(13).toInt();
        documentCodeObj["isHeader"] = documentCodeCellObj["isHeader"].toBool(query.value(10).toBool());
        documentCodeObj["isAutoGenerated"] = false;
        documentCodeObj["isEmpty"] = query.value(11).toBool();
        documentCodeObj["stretch"] = documentCodeCellObj["stretch"].toInt(100);
        documentCodeObj["isUnderline"] = documentCodeCellObj["isUnderline"].toBool(false);
        rowObj["documentCode"] = documentCodeObj;
        
        QJsonObject supplierObj;
        supplierObj["value"] = query.value(3).toString();
        supplierObj["rowNumber"] = query.value(12).toInt();
        supplierObj["pageNumber"] = query.value(13).toInt();
        supplierObj["isHeader"] = supplierCellObj["isHeader"].toBool(query.value(10).toBool());
        supplierObj["isAutoGenerated"] = false;
        supplierObj["isEmpty"] = query.value(11).toBool();
        supplierObj["stretch"] = supplierCellObj["stretch"].toInt(100);
        supplierObj["isUnderline"] = supplierCellObj["isUnderline"].toBool(false);
        rowObj["supplier"] = supplierObj;
        
        QJsonObject whereUsedObj;
        whereUsedObj["value"] = query.value(4).toString();
        whereUsedObj["rowNumber"] = query.value(12).toInt();
        whereUsedObj["pageNumber"] = query.value(13).toInt();
        whereUsedObj["isHeader"] = whereUsedCellObj["isHeader"].toBool(query.value(10).toBool());
        whereUsedObj["isAutoGenerated"] = false;
        whereUsedObj["isEmpty"] = query.value(11).toBool();
        whereUsedObj["stretch"] = whereUsedCellObj["stretch"].toInt(100);
        whereUsedObj["isUnderline"] = whereUsedCellObj["isUnderline"].toBool(false);
        rowObj["whereUsed"] = whereUsedObj;
        
        QJsonObject quantityPerItemObj;
        quantityPerItemObj["value"] = query.value(5).toString();
        quantityPerItemObj["rowNumber"] = query.value(12).toInt();
        quantityPerItemObj["pageNumber"] = query.value(13).toInt();
        quantityPerItemObj["isHeader"] = quantityPerItemCellObj["isHeader"].toBool(query.value(10).toBool());
        quantityPerItemObj["isAutoGenerated"] = false;
        quantityPerItemObj["isEmpty"] = query.value(11).toBool();
        quantityPerItemObj["stretch"] = quantityPerItemCellObj["stretch"].toInt(100);
        quantityPerItemObj["isUnderline"] = quantityPerItemCellObj["isUnderline"].toBool(false);
        rowObj["quantityPerItem"] = quantityPerItemObj;
        
        QJsonObject quantityInSetObj;
        quantityInSetObj["value"] = query.value(6).toString();
        quantityInSetObj["rowNumber"] = query.value(12).toInt();
        quantityInSetObj["pageNumber"] = query.value(13).toInt();
        quantityInSetObj["isHeader"] = quantityInSetCellObj["isHeader"].toBool(query.value(10).toBool());
        quantityInSetObj["isAutoGenerated"] = false;
        quantityInSetObj["isEmpty"] = query.value(11).toBool();
        quantityInSetObj["stretch"] = quantityInSetCellObj["stretch"].toInt(100);
        quantityInSetObj["isUnderline"] = quantityInSetCellObj["isUnderline"].toBool(false);
        rowObj["quantityInSet"] = quantityInSetObj;
        
        QJsonObject quantityForRegObj;
        quantityForRegObj["value"] = query.value(7).toString();
        quantityForRegObj["rowNumber"] = query.value(12).toInt();
        quantityForRegObj["pageNumber"] = query.value(13).toInt();
        quantityForRegObj["isHeader"] = quantityForRegCellObj["isHeader"].toBool(query.value(10).toBool());
        quantityForRegObj["isAutoGenerated"] = false;
        quantityForRegObj["isEmpty"] = query.value(11).toBool();
        quantityForRegObj["stretch"] = quantityForRegCellObj["stretch"].toInt(100);
        quantityForRegObj["isUnderline"] = quantityForRegCellObj["isUnderline"].toBool(false);
        rowObj["quantityForReg"] = quantityForRegObj;
        
        QJsonObject totalQuantityObj;
        totalQuantityObj["value"] = query.value(8).toString();
        totalQuantityObj["rowNumber"] = query.value(12).toInt();
        totalQuantityObj["pageNumber"] = query.value(13).toInt();
        totalQuantityObj["isHeader"] = totalQuantityCellObj["isHeader"].toBool(query.value(10).toBool());
        totalQuantityObj["isAutoGenerated"] = false;
        totalQuantityObj["isEmpty"] = query.value(11).toBool();
        totalQuantityObj["stretch"] = totalQuantityCellObj["stretch"].toInt(100);
        totalQuantityObj["isUnderline"] = totalQuantityCellObj["isUnderline"].toBool(false);
        rowObj["totalQuantity"] = totalQuantityObj;
        
        QJsonObject noteObj;
        noteObj["value"] = query.value(9).toString();
        noteObj["rowNumber"] = query.value(12).toInt();
        noteObj["pageNumber"] = query.value(13).toInt();
        noteObj["isHeader"] = noteCellObj["isHeader"].toBool(query.value(10).toBool());
        noteObj["isAutoGenerated"] = false;
        noteObj["isEmpty"] = query.value(11).toBool();
        noteObj["stretch"] = noteCellObj["stretch"].toInt(100);
        noteObj["isUnderline"] = noteCellObj["isUnderline"].toBool(false);
        rowObj["note"] = noteObj;
        
        rowObj["isHeader"] = query.value(10).toBool();
        rowObj["isEmpty"] = query.value(11).toBool();
        rowObj["rowNumber"] = query.value(12).toInt();
        rowObj["pageNumber"] = query.value(13).toInt();
        
        rowsArray.append(rowObj);
    }
    
    root["rows"] = rowsArray;
    
    // Добавляем настройки колонок по умолчанию
    QStringList defaultColumnMappings = {"Name", "ProductCode", "DocumentCode", "Supplier", "WhereUsed", 
                                        "QuantityPerItem", "QuantityInSet", "QuantityForReg", "TotalQuantity", "Note"};
    root["columnMappings"] = QJsonArray::fromStringList(defaultColumnMappings);
    
    // Добавляем свойства по умолчанию
    QStringList defaultPropertyNames = {"Name", "ProductCode", "DocumentCode", "Supplier", "WhereUsed", 
                                       "QuantityPerItem", "QuantityInSet", "QuantityForReg", "TotalQuantity", "Note"};
    root["propertyNames"] = QJsonArray::fromStringList(defaultPropertyNames);
    
    QJsonDocument doc(root);
    QByteArray result = doc.toJson();
    
    qDebug() << "DataBaseController::loadVedomostTable: Загружено" << rowsArray.size() << "строк";
    return result;
}

bool DataBaseController::deleteVedomostTable(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    qDebug() << "DataBaseController::deleteVedomostTable: Удаляем ведомость покупных изделий для проекта:" << projectName;
    
    QSqlQuery query = prepareQuery("DELETE FROM vedomost_rows WHERE project_name = ?");
    query.addBindValue(projectName);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления ведомости покупных изделий: " + query.lastError().text());
        return false;
    }
    
    qDebug() << "DataBaseController::deleteVedomostTable: Ведомость успешно удалена";
    emit dataChanged();
    return true;
}

QStringList DataBaseController::getAvailableVedomostProjects()
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QStringList();
    }
    
    qDebug() << "DataBaseController::getAvailableVedomostProjects: Получаем список проектов с ведомостями";
    
    QSqlQuery query = prepareQuery("SELECT DISTINCT project_name FROM vedomost_rows ORDER BY project_name");
    
    if (!query.exec()) {
        setLastError("Ошибка получения списка проектов с ведомостями: " + query.lastError().text());
        return QStringList();
    }
    
    QStringList projects;
    while (query.next()) {
        projects << query.value(0).toString();
    }
    
    return projects;
}

QString DataBaseController::getVedomostTableInfo(const QString &projectName)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return QString();
    }
    
    qDebug() << "DataBaseController::getVedomostTableInfo: Получаем информацию о ведомости покупных изделий для проекта:" << projectName;
    
    QSqlQuery query = prepareQuery(
        "SELECT COUNT(*) as total_rows, "
        "SUM(CASE WHEN is_header = 1 THEN 1 ELSE 0 END) as header_rows, "
        "SUM(CASE WHEN is_empty = 1 THEN 1 ELSE 0 END) as empty_rows, "
        "MIN(row_order) as min_order, "
        "MAX(row_order) as max_order "
        "FROM vedomost_rows WHERE project_name = ?"
    );
    query.addBindValue(projectName);
    
    if (!query.exec() || !query.next()) {
        setLastError("Ошибка получения информации о ведомости покупных изделий: " + query.lastError().text());
        return QString();
    }
    
    int totalRows = query.value(0).toInt();
    int headerRows = query.value(1).toInt();
    int emptyRows = query.value(2).toInt();
    int minOrder = query.value(3).toInt();
    int maxOrder = query.value(4).toInt();
    
    QString info = QString("Ведомость покупных изделий для проекта '%1':\n"
                          "Всего строк: %2\n"
                          "Заголовков: %3\n"
                          "Пустых строк: %4\n"
                          "Диапазон строк: %5-%6")
                          .arg(projectName)
                          .arg(totalRows)
                          .arg(headerRows)
                          .arg(emptyRows)
                          .arg(minOrder)
                          .arg(maxOrder);
    
    qDebug() << "DataBaseController::getVedomostTableInfo: Информация получена:" << info;
    return info;
}

// Работа с данными PCB
int DataBaseController::addPCBData(int layerCount)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return -1;
    }
    
    QSqlQuery query = prepareQuery("INSERT INTO pcb_data (layer_count) VALUES (?)");
    query.addBindValue(layerCount);
    
    if (!query.exec()) {
        setLastError("Ошибка добавления данных PCB: " + query.lastError().text());
        return -1;
    }
    
    return query.lastInsertId().toInt();
}

bool DataBaseController::updatePCBLayerCount(int pcbId, int layerCount)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    QSqlQuery query = prepareQuery("UPDATE pcb_data SET layer_count = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?");
    query.addBindValue(layerCount);
    query.addBindValue(pcbId);
    
    if (!query.exec()) {
        setLastError("Ошибка обновления количества слоев PCB: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

bool DataBaseController::addDielMaterial(int pcbId, const QString &name, const QString &value, double height, int dielType, int layerNumber)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    qDebug() << "DataBaseController: Добавляем диэлектрический материал:";
    qDebug() << "  pcbId:" << pcbId;
    qDebug() << "  name:" << name;
    qDebug() << "  value:" << value;
    qDebug() << "  height:" << height;
    qDebug() << "  dielType:" << dielType;
    qDebug() << "  layerNumber:" << layerNumber;
    
    QSqlQuery query = prepareQuery(
        "REPLACE INTO diel_materials (pcb_id, name, value, height, diel_type, layer_number) "
        "VALUES (?, ?, ?, ?, ?, ?)"
    );
    query.addBindValue(pcbId);
    query.addBindValue(name);
    query.addBindValue(value);
    query.addBindValue(height);
    query.addBindValue(dielType);
    query.addBindValue(layerNumber);
    
    if (!query.exec()) {
        QString errorText = "Ошибка добавления диэлектрического материала: " + query.lastError().text();
        qDebug() << "DataBaseController:" << errorText;
        setLastError(errorText);
        return false;
    }
    
    qDebug() << "DataBaseController: Диэлектрический материал успешно добавлен";
    emit dataChanged();
    return true;
}

bool DataBaseController::updateDielMaterial(int pcbId, const QString &name, const QString &value, double height, int dielType, int layerNumber)
{
    return addDielMaterial(pcbId, name, value, height, dielType, layerNumber); // REPLACE INTO
}

bool DataBaseController::removeDielMaterial(int pcbId, int layerNumber)
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    QSqlQuery query = prepareQuery("DELETE FROM diel_materials WHERE pcb_id = ? AND layer_number = ?");
    query.addBindValue(pcbId);
    query.addBindValue(layerNumber);
    
    if (!query.exec()) {
        setLastError("Ошибка удаления диэлектрического материала: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

PCBData DataBaseController::getPCBData(int pcbId)
{
    PCBData pcbData;
    pcbData.id = -1;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return pcbData;
    }
    
    QSqlQuery query = prepareQuery("SELECT id, layer_count FROM pcb_data WHERE id = ?");
    query.addBindValue(pcbId);
    
    if (query.exec() && query.next()) {
        pcbData.id = query.value(0).toInt();
        pcbData.layerCount = query.value(1).toInt();
        pcbData.dielMaterials = getDielMaterials(pcbId);
    }
    
    return pcbData;
}

QList<DielProperty> DataBaseController::getDielMaterials(int pcbId)
{
    QList<DielProperty> materials;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return materials;
    }
    
    QSqlQuery query = prepareQuery("SELECT name, value, height, diel_type, layer_number FROM diel_materials WHERE pcb_id = ? ORDER BY layer_number");
    query.addBindValue(pcbId);
    
    if (query.exec()) {
        while (query.next()) {
            DielProperty material;
            material.name = query.value(0).toString();
            material.value = query.value(1).toString();
            material.height = query.value(2).toDouble();
            material.dielType = query.value(3).toInt();
            material.layerNumber = query.value(4).toInt();
            materials << material;
        }
    }
    
    return materials;
}

PCBData DataBaseController::getPCBData()
{
    PCBData pcbData;
    pcbData.id = -1;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return pcbData;
    }
    
    // Получаем последнюю запись PCB
    QSqlQuery query = prepareQuery("SELECT id, layer_count FROM pcb_data ORDER BY id DESC LIMIT 1");
    
    if (query.exec() && query.next()) {
        int pcbId = query.value(0).toInt();
        pcbData.id = pcbId;
        pcbData.layerCount = query.value(1).toInt();
        pcbData.dielMaterials = getDielMaterials(pcbId);
        
        qDebug() << "DataBaseController: Получены данные PCB - ID:" << pcbData.id 
                 << "слоев:" << pcbData.layerCount << "материалов:" << pcbData.dielMaterials.size();
    } else {
        qDebug() << "DataBaseController: Данные PCB не найдены в БД";
    }
    
    return pcbData;
}

QList<DielProperty> DataBaseController::getDielMaterials()
{
    QList<DielProperty> materials;
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return materials;
    }
    
    // Получаем материалы для последней записи PCB
    QSqlQuery pcbQuery = prepareQuery("SELECT id FROM pcb_data ORDER BY id DESC LIMIT 1");
    
    if (pcbQuery.exec() && pcbQuery.next()) {
        int pcbId = pcbQuery.value(0).toInt();
        materials = getDielMaterials(pcbId);
        
        qDebug() << "DataBaseController: Получены материалы для PCB ID:" << pcbId 
                 << "количество:" << materials.size();
    } else {
        qDebug() << "DataBaseController: Записи PCB не найдены в БД";
    }
    
    return materials;
}

bool DataBaseController::savePCBData(const PCBData &pcbData)
{
    qDebug() << "DataBaseController: Начинаем сохранение PCB данных:";
    qDebug() << "  ID:" << pcbData.id;
    qDebug() << "  LayerCount:" << pcbData.layerCount;
    qDebug() << "  Materials count:" << pcbData.dielMaterials.size();
    
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    if (!beginTransaction()) {
        qDebug() << "DataBaseController: ОШИБКА: Не удалось начать транзакцию";
        return false;
    }
    
    int pcbId = pcbData.id;
    if (pcbId == -1) {
        // Создаем новую запись PCB
        qDebug() << "DataBaseController: Создаем новую запись PCB";
        pcbId = addPCBData(pcbData.layerCount);
        if (pcbId == -1) {
            qDebug() << "DataBaseController: ОШИБКА: Не удалось создать запись PCB";
            rollbackTransaction();
            return false;
        }
        qDebug() << "DataBaseController: Создана запись PCB с ID:" << pcbId;
    } else {
        // Обновляем существующую запись
        qDebug() << "DataBaseController: Обновляем существующую запись PCB с ID:" << pcbId;
        if (!updatePCBLayerCount(pcbId, pcbData.layerCount)) {
            qDebug() << "DataBaseController: ОШИБКА: Не удалось обновить запись PCB";
            rollbackTransaction();
            return false;
        }
    }
    
    // Сохраняем диэлектрические материалы
    qDebug() << "DataBaseController: Сохраняем" << pcbData.dielMaterials.size() << "материалов";
    for (int i = 0; i < pcbData.dielMaterials.size(); i++) {
        const DielProperty &material = pcbData.dielMaterials[i];
        qDebug() << "DataBaseController: Сохраняем материал" << i << ":" << material.name << "=" << material.value << "слой:" << material.layerNumber;
        
        if (!addDielMaterial(pcbId, material.name, material.value, material.height, material.dielType, material.layerNumber)) {
            qDebug() << "DataBaseController: ОШИБКА: Не удалось сохранить материал" << i;
            rollbackTransaction();
            return false;
        }
    }
    
    if (!commitTransaction()) {
        qDebug() << "DataBaseController: ОШИБКА: Не удалось завершить транзакцию";
        rollbackTransaction();
        return false;
    }
    
    qDebug() << "DataBaseController: PCB данные успешно сохранены";
    return true;
}

bool DataBaseController::clearPCBData()
{
    if (!m_database.isOpen()) {
        setLastError("База данных не открыта");
        return false;
    }
    
    QSqlQuery query = prepareQuery("DELETE FROM pcb_data");
    
    if (!query.exec()) {
        setLastError("Ошибка очистки данных PCB: " + query.lastError().text());
        return false;
    }
    
    emit dataChanged();
    return true;
}

