#include "altiumparser.h"
#include "databasecontroller.h"
#include "../model/componentmodel.h"
#include <QFileInfo>
#include <QFile>
#include <QTextStream>
#include <QRegularExpression>
#include <QTextCodec>
#include <QDir>
#include <QMessageBox>

AltiumParser::AltiumParser(QObject *parent)
    : QObject(parent)
    , m_isPcbMultilayer(false)
    , m_database(nullptr)
    , m_parseWatcher(nullptr)
    , m_isParsingAsync(false)
    , m_pcbDocFileName("")
{
    initializeRegex();
    
    // Инициализируем watcher для асинхронного парсинга
    m_parseWatcher = new QFutureWatcher<bool>(this);
    connect(m_parseWatcher, &QFutureWatcher<bool>::finished, 
            this, &AltiumParser::onParseFinished);
    connect(m_parseWatcher, &QFutureWatcher<bool>::progressValueChanged,
            this, &AltiumParser::onParseProgress);
}

AltiumParser::~AltiumParser()
{
}

bool AltiumParser::parseSchFile(const QString &filename, ComponentModel *model)
{
    if (!model) {
        setError("Модель компонентов не инициализирована");
        return false;
    }
    
    // TODO: Реализовать парсинг .sch файлов
    setError("Парсинг .sch файлов еще не реализован");
    return false;
}

bool AltiumParser::parsePcbFile(const QString &filename, ComponentModel *model)
{
    if (!model) {
        setError("Модель компонентов не инициализирована");
        return false;
    }
    
    // TODO: Реализовать парсинг .pcb файлов
    setError("Парсинг .pcb файлов еще не реализован");
    return false;
}

bool AltiumParser::parseBomFile(const QString &filename, ComponentModel *model)
{
    if (!model) {
        setError("Модель компонентов не инициализирована");
        return false;
    }
    
    // TODO: Реализовать парсинг BOM файлов
    setError("Парсинг BOM файлов еще не реализован");
    return false;
}

bool AltiumParser::parseSchDoc(const QString &filename, ComponentModel *model)
{
    if (!model) {
        setError("Модель компонентов не инициализирована");
        return false;
    }
    
    // TODO: Реализовать парсинг .SchDoc файлов
    setError("Парсинг .SchDoc файлов еще не реализован");
    return false;
}

bool AltiumParser::parsePcbDoc(const QString &filename, ComponentModel *model)
{
    if (!model) {
        setError("Модель компонентов не инициализирована");
        return false;
    }
    
    // TODO: Реализовать парсинг .PcbDoc файлов
    setError("Парсинг .PcbDoc файлов еще не реализован");
    return false;
}

bool AltiumParser::parseCsvBom(const QString &filename, ComponentModel *model)
{
    if (!model) {
        setError("Модель компонентов не инициализирована");
        return false;
    }
    
    // TODO: Реализовать парсинг CSV BOM файлов
    setError("Парсинг CSV BOM файлов еще не реализован");
    return false;
}

bool AltiumParser::parseXlsBom(const QString &filename, ComponentModel *model)
{
    if (!model) {
        setError("Модель компонентов не инициализирована");
        return false;
    }
    
    // TODO: Реализовать парсинг XLS BOM файлов
    setError("Парсинг XLS BOM файлов еще не реализован");
    return false;
}

// Новый метод для парсинга PrjPcb файлов
bool AltiumParser::parsePrjPcbFile(const QString &filename, ComponentModel *model)
{
    if (!model) {
        setError("Модель компонентов не инициализирована");
        return false;
    }
    
    if (!QFile::exists(filename)) {
        setError("Файл не существует: " + filename);
        return false;
    }
    
    clearError();
    emit parsingProgress(0);
    
    // Очищаем предыдущие данные
    m_componentsList.clear();
    m_variantsList.clear();
    m_dielMaterialsList.clear();
    m_projectParamsList.clear();
    m_variantNamesList.clear();
    m_isPcbMultilayer = false;
    
    // Очищаем базу данных
    if (m_database) {
        m_database->clearAllData();
    }
    
    emit parsingProgress(10);
    
    bool success = parseProjectFile(filename, model);
    
    if (success) {
        emit parsingProgress(100);
        emit parsingFinished(true);
    } else {
        emit parsingFinished(false);
    }
    
    return success;
}

bool AltiumParser::parseProjectFile(const QString &filename, ComponentModel *model)
{
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        setError("Не удалось открыть файл: " + filename);
        return false;
    }
    
    QTextStream reader(&file);
    reader.setCodec(QTextCodec::codecForName("Windows-1251"));
    
    // Очищаем базу данных
    if (m_database) {
        m_database->clearAllData();
    }
    
    // Сначала подсчитываем общее количество строк для равномерного прогресса
    QFile countFile(filename);
    countFile.open(QIODevice::ReadOnly | QIODevice::Text);
    QTextStream countReader(&countFile);
    countReader.setCodec(QTextCodec::codecForName("Windows-1251"));
    
    int totalLines = 0;
    while (!countReader.atEnd()) {
        countReader.readLine();
        totalLines++;
    }
    countFile.close();
    
    // Открываем файл заново для парсинга
    file.seek(0);
    
    // Инициализация структур данных
    ProjectData projectData;
    projectData.variantNames.append("No Variations");
    projectData.pcbLayerCount = 0;
    projectData.pcbDielMaterials.clear();
    
    QString prevPrjStr, prevPrevPrjStr;
    int lineCount = 0;
    int lastProgress = 0;
    
    while (!reader.atEnd()) {
        QString prjStr = reader.readLine().trimmed();
        lineCount++;
        
        // Обновляем прогресс каждые 100 строк или при достижении определенного процента
        int currentProgress = (lineCount * 80) / totalLines; // 80% для парсинга
        if (currentProgress > lastProgress) {
            emit parsingProgress(currentProgress);
            lastProgress = currentProgress;
        }
        
        // Обработка различных типов строк
        parseProjectVariantSection(prjStr, projectData);
        parseComponentVariations(prjStr, projectData);
        parseProjectParameters(prevPrevPrjStr, prevPrjStr, prjStr, projectData);
        parseSchDocFiles(prjStr, filename, projectData);
        parsePcbDocFiles(prjStr, filename, projectData);
        
        prevPrevPrjStr = prevPrjStr;
        prevPrjStr = prjStr;
    }
    
    file.close();
    
    // Вывод результатов парсинга
    printParsingResults(projectData);
    
    // Сохранение данных в базу (20% прогресса)
    emit parsingProgress(80);
    saveDataToDatabase(projectData);
    
    // Сохраняем имя PcbDoc файла
    m_pcbDocFileName = projectData.pcbDocFileName;
    
    // Установка данных в модель
    emit parsingProgress(90);
    setupModelData(projectData, model);
    
    return true;
}

// Обработка секций вариантов проекта
void AltiumParser::parseProjectVariantSection(const QString &prjStr, ProjectData &data)
{
    // Обработка [ProjectVariant]
    if (prjStr.length() > 15 && prjStr.left(15).toUpper() == "[PROJECTVARIANT") {
        data.componentVariantPropList.clear();
        data.isWaitingVariantDescription = true;
        QString cleanStr = prjStr;
        cleanStr.replace(']', QChar());
        data.currentVariantNumber = cleanStr.mid(15).toInt();
    }
    
    // Обработка ParamVariationCount
    if (prjStr.length() > 18 && prjStr.left(19).toUpper() == "PARAMVARIATIONCOUNT") {
        finalizeCurrentVariant(data);
    }
    
    // Обработка Description
    if (prjStr.length() > 12 && data.isWaitingVariantDescription && 
        prjStr.left(12).toUpper() == "DESCRIPTION=") {
        data.isWaitingVariantDescription = false;
        QString variantName = prjStr.mid(12);
        data.variantNames.append(variantName);
    }
}

// Завершение текущего варианта
void AltiumParser::finalizeCurrentVariant(ProjectData &data)
{
    if (data.componentVariantPropList.size() > 0) {
        data.componentsPropVariantList.append(data.componentVariantPropList);
        data.componentVariantPropList.clear();
    }
    
    if (data.componentsPropVariantList.size() > 0) {
        data.componentsVariantList.append(data.componentsPropVariantList);
        data.componentsPropVariantList.clear();
    }
    
    data.dnfVariantDesignatorsList.append(data.dnfDesignatorsList);
    data.fittedVariantDesignatorsList.append(data.fittedDesignatorsList);
    data.dnfDesignatorsList.clear();
    data.fittedDesignatorsList.clear();
}

// Обработка вариаций компонентов
void AltiumParser::parseComponentVariations(const QString &prjStr, ProjectData &data)
{
    if (prjStr.length() <= 9) return;
    
    QStringList prjStrArray = prjStr.split('|');
    if (prjStrArray.isEmpty()) return;
    
    QStringList valuesArray = prjStrArray[0].split('=');
    if (valuesArray.size() <= 2) return;
    
    // Обработка VARIATION=DESIGNATOR
    if (valuesArray[0].length() >= 9 && valuesArray[0].left(9).toUpper() == "VARIATION") {
        if (valuesArray[1].left(10).toUpper() == "DESIGNATOR") {
            parseVariationDesignator(prjStrArray, valuesArray, data);
        }
    }
    
    // Обработка PARAMVARIATION=PARAMETERNAME
    if (valuesArray[0].length() >= 14 && valuesArray[0].left(14).toUpper() == "PARAMVARIATION") {
        if (valuesArray[1].toUpper() == "PARAMETERNAME") {
            parseParamVariation(prjStrArray, valuesArray, data);
        }
    }
}

// Парсинг VARIATION=DESIGNATOR
void AltiumParser::parseVariationDesignator(const QStringList &prjStrArray, 
                                           const QStringList &valuesArray, 
                                           ProjectData &data)
{
    if (data.componentVariantPropList.size() > 0) {
        data.componentsPropVariantList.append(data.componentVariantPropList);
        data.componentVariantPropList.clear();
    }
    
    ComponentProperty prop;
    prop.name = "Designator";
    prop.text = valuesArray[2];
    QString designator = valuesArray[2];
    
    data.componentVariantPropList.append(prop);
    
    // Обработка KIND
    if (prjStrArray.size() > 1) {
        QStringList kindValues = prjStrArray[2].split('=');
        if (kindValues[0].toUpper() == "KIND") {
            ComponentProperty kindProp;
            kindProp.name = "Kind";
            kindProp.text = kindValues[1];
            
            data.componentVariantPropList.append(kindProp);
            
            if (kindValues[1] == "1") {
                data.dnfDesignatorsList.append(designator);
            } else {
                data.fittedDesignatorsList.append(designator);
            }
        }
    }
}

// Парсинг PARAMVARIATION=PARAMETERNAME
void AltiumParser::parseParamVariation(const QStringList &prjStrArray, 
                                      const QStringList &valuesArray, 
                                      ProjectData &data)
{
    ComponentProperty prop;
    prop.name = valuesArray[2];
    
    // Считываем VariantValue
    int idx = prjStrArray[1].indexOf('=');
    if (idx >= 0) {
        prop.text = prjStrArray[1].mid(idx + 1);
    } else {
        prop.text = prjStrArray[1];
    }
    
    data.componentVariantPropList.append(prop);
}

// Обработка параметров проекта
void AltiumParser::parseProjectParameters(const QString &prevPrevPrjStr, 
                                        const QString &prevPrjStr, 
                                        const QString &prjStr, 
                                        ProjectData &data)
{
    if (prevPrevPrjStr.length() <= 10 || prevPrjStr.length() <= 4 || prjStr.length() <= 5) {
        return;
    }
    
    if (prevPrevPrjStr.left(10).toUpper() == "[PARAMETER" &&
        prevPrjStr.left(4).toUpper() == "NAME" &&
        prjStr.left(5).toUpper() == "VALUE") {
        
        QString cleanPrevPrev = prevPrevPrjStr;
        cleanPrevPrev.replace(']', QChar());
        QStringList paramPrjStrArray = cleanPrevPrev.split('_');
        int variantNumber = (paramPrjStrArray.size() > 1) ? data.currentVariantNumber : 0;
        
        QStringList nameValue;
        nameValue.append(prevPrjStr.split('=')[1]);
        nameValue.append(prjStr.split('=')[1]);
        
        while (data.prjParamsVariantList.size() <= variantNumber) {
            data.prjParamsVariantList.append(QList<QStringList>());
        }
        
        data.prjParamsVariantList[variantNumber].append(nameValue);
    }
}

// Обработка файлов схем
void AltiumParser::parseSchDocFiles(const QString &prjStr, const QString &filename, ProjectData &data)
{
    if (prjStr.length() <= 13) return;
    
    if (prjStr.left(13).toUpper() == "DOCUMENTPATH=" && prjStr.right(6).toUpper() == "SCHDOC") {
        QString schPath = QDir(QFileInfo(filename).absolutePath()).filePath(prjStr.mid(13));
        
        if (QFile::exists(schPath)) {
            int componentsBefore = data.componentsList.size();
            parseSchDocFile(schPath, data.componentsList);
            int componentsAfter = data.componentsList.size();
        }
    }
}

// Обработка файлов плат
void AltiumParser::parsePcbDocFiles(const QString &prjStr, const QString &filename, ProjectData &data)
{
    if (prjStr.length() <= 13) return;
    
    if (prjStr.left(13).toUpper() == "DOCUMENTPATH=" && prjStr.right(6).toUpper() == "PCBDOC") {
        QString pcbPath = QDir(QFileInfo(filename).absolutePath()).filePath(prjStr.mid(13));
        
        if (QFile::exists(pcbPath)) {
            bool parseResult = parsePcbDocFile(pcbPath, data.pcbDielMaterials, data.pcbLayerCount);
            // Сохраняем имя PcbDoc файла
            if (parseResult) {
                data.pcbDocFileName = pcbPath;
            }
        }
    }
}

// Вывод результатов парсинга
void AltiumParser::printParsingResults(const ProjectData &data)
{
}

// Сохранение данных в базу данных
void AltiumParser::saveDataToDatabase(const ProjectData &data)
{
    if (!m_database) {
        return;
    }
    
    // Сначала создаем варианты в БД (80-85%)
    emit parsingProgress(80);
    saveVariantsToDatabase(data);
    
    // Сохраняем обычные компоненты (85-90%)
    emit parsingProgress(85);
    saveRegularComponents(data);
    
    // Сохраняем вариативные свойства (90-95%)
    emit parsingProgress(90);
    saveVariantProperties(data);
    
    // Сохраняем параметры проекта (95-100%)
    emit parsingProgress(95);
    saveProjectParameters(data);
    
    // Сохраняем данные PCB (97-100%)
    emit parsingProgress(97);
    savePCBDataToDatabase(data);
    
    emit parsingProgress(100);
}

// Сохранение вариантов в базу данных
void AltiumParser::saveVariantsToDatabase(const ProjectData &data)
{
    for (const QString &variantName : data.variantNames) {
        // Проверяем, существует ли вариант
        int variantId = m_database->getVariantId(variantName);
        if (variantId == -1) {
            // Создаем новый вариант
            variantId = m_database->addVariant(variantName);
        }
    }
}

// Сохранение обычных компонентов
void AltiumParser::saveRegularComponents(const ProjectData &data)
{
    if (data.componentsList.isEmpty()) {
        return;
    }
    
    // Начинаем транзакцию для пакетной вставки
    if (!m_database->beginTransaction()) {
        return;
    }
    
    int savedComponents = 0;
    
    for (const QList<ComponentProperty> &componentProps : data.componentsList) {
        QString designator;
        QMap<QString, QString> properties;
        
        for (const ComponentProperty &prop : componentProps) {
            if (prop.name == "Designator") {
                designator = prop.text;
            } else {
                properties[prop.name] = prop.text;
            }
        }
        
        if (!designator.isEmpty()) {
            // Используем пакетную вставку
            bool success = m_database->addComponentBatch(designator, properties);
            if (success) {
                savedComponents++;
                
                // Получаем ID добавленного компонента для связи с вариантами
                ComponentData componentData = m_database->getComponent(designator);
                if (componentData.id != -1) {
                    // Добавляем компонент во все варианты пакетно
                    m_database->addComponentVariantsBatch(componentData.id, data.variantNames);
                }
            }
        }
    }
    
    // Завершаем транзакцию
    if (!m_database->commitTransaction()) {
        m_database->rollbackTransaction();
    }
}

// Сохранение вариативных свойств
void AltiumParser::saveVariantProperties(const ProjectData &data)
{
    for (int variantIndex = 0; variantIndex < data.componentsVariantList.size(); variantIndex++) {
        const QList<QList<ComponentProperty>> &variantComponents = data.componentsVariantList[variantIndex];
        
        // Получаем название варианта (пропускаем "No Variations")
        if (variantIndex + 1 >= data.variantNames.size()) {
            continue;
        }
        
        QString variantName = data.variantNames[variantIndex + 1];
        int variantId = m_database->getVariantId(variantName);
        
        if (variantId == -1) {
            continue;
        }
        
        for (const QList<ComponentProperty> &componentProps : variantComponents) {
            QString designator;
            QMap<QString, QString> properties;
            
            for (const ComponentProperty &prop : componentProps) {
                if (prop.name == "Designator") {
                    designator = prop.text;
                } else {
                    properties[prop.name] = prop.text;
                }
            }
            
            if (!designator.isEmpty()) {
                
                // Получаем ID компонента
                ComponentData componentData = m_database->getComponent(designator);
                int componentId = componentData.id;
                
                if (componentId != -1) {
                    // Добавляем вариативные свойства
                    for (auto it = properties.begin(); it != properties.end(); ++it) {
                        m_database->setVariantProperty(componentId, variantId, it.key(), it.value());
                    }
                    
                    // Устанавливаем статус DNF/Fitted
                    bool isDnf = false;
                    if (variantIndex < data.dnfVariantDesignatorsList.size()) {
                        isDnf = data.dnfVariantDesignatorsList[variantIndex].contains(designator);
                    }
                    
                    m_database->setComponentVariantFitted(componentId, variantId, !isDnf);
                }
            }
        }
    }
}

// Сохранение параметров проекта
void AltiumParser::saveProjectParameters(const ProjectData &data)
{
    if (!m_database) return;

    // Создаем плоский список всех свойств компонентов для обработки сложных строк
    QList<ComponentProperty> allComponentProps;
    for (const QList<ComponentProperty> &componentProps : data.componentsList) {
        allComponentProps.append(componentProps);
    }

    for (int variantIndex = 0; variantIndex < data.prjParamsVariantList.size(); variantIndex++) {
        const QList<QStringList> &variantParams = data.prjParamsVariantList[variantIndex];
        QString variantName = (variantIndex < data.variantNames.size()) ? data.variantNames[variantIndex] : "No Variations";

        for (const QStringList &param : variantParams) {
            if (param.size() >= 2) {
                QString name = param[0];
                QString value = param[1];

                // Обработка сложных строк вида ='prop1'+'prop2' или ="prop1"+"prop2"
                value = makeComplexStringIfItIs(value, allComponentProps);

                m_database->setProjectParam(name, value);
            }
        }
    }
}

// Сохранение данных PCB в базу данных
void AltiumParser::savePCBDataToDatabase(const ProjectData &data)
{
    if (!m_database) {
        return;
    }

    // Создаем структуру PCBData
    PCBData pcbData;
    pcbData.id = -1; // Новая запись
    pcbData.layerCount = data.pcbLayerCount;
    pcbData.dielMaterials = data.pcbDielMaterials;

    // Сохраняем данные PCB
    m_database->savePCBData(pcbData);
}

// Установка данных в модель
void AltiumParser::setupModelData(const ProjectData &data, ComponentModel *model)
{
    // Устанавливаем данные в модель
    m_componentsList = data.componentsList;
    m_variantNamesList = data.variantNames;
    
    // Создаем варианты
    m_variantsList.clear();
    for (const QString &variantName : data.variantNames) {
        VariantInfo variant;
        variant.name = variantName;
        variant.dnfDesignators = QStringList();
        variant.fittedDesignators = QStringList();
        variant.componentVariants = QList<QList<ComponentProperty>>();
        variant.parameters = QList<QMap<QString, QString>>();
        m_variantsList.append(variant);
    }
    

}

QString AltiumParser::findParamDesignator(QTextStream &reader, const QString &paramNumber)
{
    qint64 currentPos = reader.pos();
    QString designator;
    
    // Читаем следующие строки для поиска ParamDesignator
    for (int i = 0; i < 10; i++) {
        QString line = reader.readLine().trimmed();
        if (line.startsWith("ParamDesignator" + paramNumber + "=")) {
            designator = line.mid(15 + paramNumber.length() + 1);
            break;
        }
    }
    
    // Возвращаемся к исходной позиции
    reader.seek(currentPos);
    
    return designator;
}

QString AltiumParser::makeComplexStringIfItIs(const QString &text, const QList<ComponentProperty> &componentProps)
{
    if (text.isEmpty() || text[0] != '=') {
        return text;
    }
    
    QString result = text.mid(1); // Убираем '='
    
    // Обрабатываем сложные строки вида ='prop1'+'prop2' или ="prop1"+"prop2"
    QRegularExpression regex(R"(['"]([^'"]+)['"])");
    QRegularExpressionMatchIterator it = regex.globalMatch(result);
    
    while (it.hasNext()) {
        QRegularExpressionMatch match = it.next();
        QString propName = match.captured(1);
        
        // Ищем значение свойства
        QString propValue;
        for (const ComponentProperty &prop : componentProps) {
            if (prop.name == propName) {
                propValue = prop.text;
                break;
            }
        }
        
        // Заменяем в результате
        result.replace(match.captured(0), propValue);
    }
    
    return result;
}

QString AltiumParser::makeDesignatorForOrdering(const QString &designator)
{
    // Извлекаем буквенную и числовую части
    QRegularExpression regex(R"(([A-Za-z]+)(\d+))");
    QRegularExpressionMatch match = regex.match(designator);
    
    if (match.hasMatch()) {
        QString letters = match.captured(1);
        QString numbers = match.captured(2);
        
        // Форматируем для правильной сортировки
        return letters.toUpper() + numbers.rightJustified(5, '0');
    }
    
    return designator.toUpper();
}

QString AltiumParser::extractComponentDesignation(const QString &line)
{
    Q_UNUSED(line)
    // TODO: Реализовать извлечение обозначения компонента
    return QString();
}

QString AltiumParser::extractComponentName(const QString &line)
{
    Q_UNUSED(line)
    // TODO: Реализовать извлечение наименования компонента
    return QString();
}

QString AltiumParser::extractComponentValue(const QString &line)
{
    Q_UNUSED(line)
    // TODO: Реализовать извлечение номинала компонента
    return QString();
}

QString AltiumParser::extractComponentFootprint(const QString &line)
{
    Q_UNUSED(line)
    // TODO: Реализовать извлечение корпуса компонента
    return QString();
}

QString AltiumParser::extractComponentManufacturer(const QString &line)
{
    Q_UNUSED(line)
    // TODO: Реализовать извлечение производителя компонента
    return QString();
}

QString AltiumParser::extractComponentPartNumber(const QString &line)
{
    Q_UNUSED(line)
    // TODO: Реализовать извлечение партномера компонента
    return QString();
}

int AltiumParser::extractComponentQuantity(const QString &line)
{
    Q_UNUSED(line)
    // TODO: Реализовать извлечение количества компонента
    return 1;
}

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

void AltiumParser::clearError()
{
    m_lastError.clear();
}

QString AltiumParser::getPcbDocFileName() const
{
    return m_pcbDocFileName;
}

void AltiumParser::initializeRegex()
{
    // Инициализация регулярных выражений для парсинга
    m_designationRegex = QRegularExpression(R"(([A-Z][0-9]+))");
    m_nameRegex = QRegularExpression(R"(([A-Za-zА-Яа-я\s]+))");
    m_valueRegex = QRegularExpression(R"(([0-9]+[A-Za-z]*))");
    m_footprintRegex = QRegularExpression(R"(([A-Za-z0-9_-]+))");
    m_manufacturerRegex = QRegularExpression(R"(([A-Za-zА-Яа-я\s]+))");
    m_partNumberRegex = QRegularExpression(R"(([A-Za-z0-9_-]+))");
    m_quantityRegex = QRegularExpression(R"(([0-9]+))");
    

}

bool AltiumParser::parseSchLine(const QString &line, QMap<QString, QString> &component)
{
    Q_UNUSED(line)
    Q_UNUSED(component)
    // TODO: Реализовать парсинг строки схемы
    return false;
}

bool AltiumParser::parsePcbLine(const QString &line, QMap<QString, QString> &component)
{
    Q_UNUSED(line)
    Q_UNUSED(component)
    // TODO: Реализовать парсинг строки печатной платы
    return false;
}

bool AltiumParser::parseBomLine(const QString &line, QMap<QString, QString> &component)
{
    Q_UNUSED(line)
    Q_UNUSED(component)
    // TODO: Реализовать парсинг строки BOM
    return false;
}

QString AltiumParser::cleanString(const QString &str)
{
    return str.trimmed();
}

bool AltiumParser::isValidComponent(const QMap<QString, QString> &component)
{
    Q_UNUSED(component)
    // TODO: Реализовать валидацию компонента
    return true;
}

void AltiumParser::setError(const QString &error)
{
    m_lastError = error;
    emit parsingError(error);
}

DataBaseController* AltiumParser::getDatabase() const
{
    return m_database;
}

void AltiumParser::setDatabase(DataBaseController *database)
{
    m_database = database;
}

// Асинхронный парсинг
bool AltiumParser::parseFileAsync(const QString &filename, ComponentModel *model)
{
    if (m_isParsingAsync) {
        return false;
    }
    
    m_isParsingAsync = true;
    emit parsingStarted();
    emit parsingProgress(0);
    
    // Запускаем парсинг в отдельном потоке
    QFuture<bool> future = QtConcurrent::run([this, filename, model]() {
        return parsePrjPcbFile(filename, model);
    });
    
    m_parseWatcher->setFuture(future);
    return true;
}

bool AltiumParser::isParsingAsync() const
{
    return m_isParsingAsync;
}

void AltiumParser::cancelParsing()
{
    if (m_isParsingAsync && m_parseWatcher->isRunning()) {

        m_parseWatcher->cancel();
        m_isParsingAsync = false;
    }
}

void AltiumParser::onParseFinished()
{
    bool success = m_parseWatcher->result();
    m_isParsingAsync = false;
    

    
    if (success) {
        emit parsingProgress(100);
        emit parsingFinished(true);
    } else {
        emit parsingFinished(false);
        emit parsingError(m_lastError);
    }
}

void AltiumParser::onParseProgress(int progress)
{
    emit parsingProgress(progress);
}

bool AltiumParser::parseSchDocFile(const QString &filename, QList<QList<ComponentProperty>> &componentsList)
{
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }
    
    QTextStream reader(&file);
    reader.setCodec(QTextCodec::codecForName("Windows-1251"));
    
    QList<ComponentProperty> componentPropList;
    QList<ComponentProperty> otherPropList;
    bool isNoBom = false;
    bool isFirstPartOfComponent = true;
    bool isComponent = false;
    int numberOfStrings = 0;
    
    while (!reader.atEnd()) {
        QString schStr = reader.readLine().trimmed();
        QStringList schStrArray = schStr.split('|');
        
        for (int i = 0; i < schStrArray.size() - 1; i++) {
            if (isComponent == true) {
                if (schStrArray[i].length() >= 23) {
                    if (schStrArray[i].left(23).toUpper() == "COMPONENTKINDVERSION2=5") {
                        isNoBom = true;
                    }
                }
                
                if (schStrArray[i].length() >= 15) {
                    if (schStrArray[i].left(14).toUpper() == "CURRENTPARTID=") {
                        if (schStrArray[i].left(15).toUpper() != "CURRENTPARTID=1" || schStrArray[i].length() > 15) {
                            isFirstPartOfComponent = false;
                        }
                    }
                }
                
                if (schStrArray[i].length() > 5 && schStrArray[i + 1].length() > 5) {
                    if (schStrArray[i].left(5).toUpper() == "TEXT=" && schStrArray[i + 1].left(5).toUpper() == "NAME=") {
                        ComponentProperty prop;
                        prop.name = schStrArray[i + 1].mid(5);
                        prop.text = schStrArray[i].mid(5);
                        
                        if (isNoBom == false) {
                            componentPropList.append(prop);
                        }
                    }
                }
                
                if (schStrArray[i].length() >= 8) {
                    if (schStrArray[i].left(7).toUpper() == "HEADER=" || (schStrArray[i].toUpper() == "RECORD=1" && schStrArray[i].length() == 8)) {
                        if (isNoBom == false && componentPropList.size() > 0 && isFirstPartOfComponent == true) {
                            componentsList.append(componentPropList);
                            numberOfStrings++;
                        }
                        
                        isNoBom = false;
                        isComponent = false;
                        isFirstPartOfComponent = true;
                        componentPropList.clear();
                    }
                }
            } else if (isComponent == false) {
                // Запись полей основной надписи в базу данных проекта
                if (schStrArray[i].length() > 5 && schStrArray[i + 1].length() > 5) {
                    if (schStrArray[i].left(5).toUpper() == "TEXT=" && schStrArray[i + 1].left(5).toUpper() == "NAME=") {
                        ComponentProperty prop;
                        prop.name = schStrArray[i + 1].mid(5);
                        prop.text = schStrArray[i].mid(5);
                        
                        otherPropList.append(prop);
                    }
                }
            }
            
            // Ищем все записи компонента
            if (schStrArray[i].length() == 8) {
                if (schStrArray[i].left(8).toUpper() == "RECORD=1") {
                    isComponent = true;
                }
            }
        }
    }
    
    // Работа с составными именами типа ='prop1'+'prop2'
    for (int i = 0; i < otherPropList.size(); i++) {
        otherPropList[i].text = makeComplexStringIfItIs(otherPropList[i].text, otherPropList);
    }
    
    qDebug() << "AltiumParser: Парсинг схемы завершен, найдено компонентов:" << numberOfStrings;
    
    file.close();
    return true;
}

bool AltiumParser::parsePcbDocFile(const QString &filename, QList<DielProperty> &dielMaterials, int &pcbLayersCount)
{
    qDebug() << "AltiumParser PCB: Начинаем парсинг файла платы:" << filename;
    
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "AltiumParser PCB: Не удалось открыть файл платы:" << filename;
        return false;
    }
    
    pcbLayersCount = 0;
    dielMaterials.clear();
    
    QTextStream in(&file);
    in.setCodec(QTextCodec::codecForName("Windows-1251"));
    
    qDebug() << "AltiumParser PCB: Начинаем чтение файла построчно...";
    
    // Переменные для поиска LAYERSET
    QString signalLayersetNumber;
    QString layersetLayers;
    
    while (!in.atEnd()) {
        QString line = in.readLine();
        QStringList parts = line.split('|');
        
        for (int i = 0; i < parts.size() - 1; i++) {
            QString part = parts[i];
            
            // Ищем LAYERSETxNAME=&Signal Layers
            if (part.startsWith("LAYERSET") && part.contains("NAME=&Signal Layers")) {
                QRegularExpression layersetNameRegex(R"(LAYERSET(\d+)NAME=&Signal Layers)");
                QRegularExpressionMatch match = layersetNameRegex.match(part);
                if (match.hasMatch()) {
                    signalLayersetNumber = match.captured(1);
                }
            }
            
            // Ищем соответствующий LAYERSETxLAYERS=
            if (!signalLayersetNumber.isEmpty() && part.startsWith(QString("LAYERSET%1LAYERS=").arg(signalLayersetNumber))) {
                layersetLayers = part.mid(QString("LAYERSET%1LAYERS=").arg(signalLayersetNumber).length());
                
                // Сбрасываем счетчик слоев перед подсчетом
                pcbLayersCount = 0;
                
                // Подсчитываем слои, исключая MultiLayer
                QStringList layers = layersetLayers.split(',');
                for (const QString &layer : layers) {
                    if (layer.trimmed() != "MultiLayer") {
                        pcbLayersCount++;
                    }
                }
            }
            
            // Ищем записи V9_STACK_LAYER для подсчета слоев (старый метод как fallback)
            if (part.startsWith("V9_STACK_LAYER") && part.contains("_NAME=")) {
                // Извлекаем номер слоя из записи V9_STACK_LAYER{номер}_NAME=
                QRegularExpression layerRegex(R"(V9_STACK_LAYER(\d+)_NAME=)");
                QRegularExpressionMatch match = layerRegex.match(part);
                if (match.hasMatch()) {
                    int layerNumber = match.captured(1).toInt();
                    if (layerNumber > pcbLayersCount) {
                        pcbLayersCount = layerNumber + 1; // +1 потому что нумерация с 0
                    }
                }
            }
            
            // Ищем записи V9_STACK_LAYER с диэлектрическими свойствами
            if (part.startsWith("V9_STACK_LAYER") && part.contains("_DIELTYPE=")) {
                // Извлекаем номер слоя и тип диэлектрика
                QRegularExpression dielTypeRegex(R"(V9_STACK_LAYER(\d+)_DIELTYPE=(\d+))");
                QRegularExpressionMatch match = dielTypeRegex.match(part);
                if (match.hasMatch()) {
                    QString layerNumber = match.captured(1);
                    int dielType = match.captured(2).toInt();
                    
                    // Создаем новый материал
                    DielProperty material;
                    material.dielType = dielType;
                    material.layerNumber = layerNumber.toInt();
                    
                    // Ищем толщину для этого слоя
                    QString heightKey = QString("V9_STACK_LAYER%1_DIELHEIGHT=").arg(layerNumber);
                    QString materialKey = QString("V9_STACK_LAYER%1_DIELMATERIAL=").arg(layerNumber);
                    
                    // Ищем в текущей строке и следующих частях
                    for (int j = i; j < parts.size(); j++) {
                        QString searchPart = parts[j];
                        
                        // Ищем толщину
                        if (searchPart.startsWith(heightKey)) {
                            QString heightStr = searchPart.mid(heightKey.length());
                            if (heightStr.endsWith("mil")) {
                                heightStr.chop(3);
                            }
                            bool ok;
                            double height = heightStr.toDouble(&ok);
                            if (ok) {
                                material.height = height * 0.0254; // Конвертация в мм
                            }
                        }
                        
                        // Ищем материал
                        if (searchPart.startsWith(materialKey)) {
                            material.name = "DielMaterial";
                            material.value = searchPart.mid(materialKey.length());
                            
                            // Добавляем материал в список, если у нас есть все данные
                            if (!material.value.isEmpty() && material.height > 0) {
                                dielMaterials.append(material);
                            }
                            break;
                        }
                    }
                }
            }
            
            // Также ищем записи LAYER_V8_ для совместимости со старым форматом
            if (part.startsWith("LAYER_V8_") && part.contains("_DIELTYPE=")) {
                QRegularExpression layerV8Regex(R"(LAYER_V8_(\d+)_DIELTYPE=(\d+))");
                QRegularExpressionMatch match = layerV8Regex.match(part);
                if (match.hasMatch()) {
                    QString layerNumber = match.captured(1);
                    int dielType = match.captured(2).toInt();
                    
                    DielProperty material;
                    material.dielType = dielType;
                    
                    QString heightKey = QString("LAYER_V8_%1_DIELHEIGHT=").arg(layerNumber);
                    QString materialKey = QString("LAYER_V8_%1_DIELMATERIAL=").arg(layerNumber);
                    
                    for (int j = i; j < parts.size(); j++) {
                        QString searchPart = parts[j];
                        
                        if (searchPart.startsWith(heightKey)) {
                            QString heightStr = searchPart.mid(heightKey.length());
                            if (heightStr.endsWith("mil")) {
                                heightStr.chop(3);
                            }
                            bool ok;
                            double height = heightStr.toDouble(&ok);
                            if (ok) {
                                material.height = height * 0.0254;
                            }
                        }
                        
                        if (searchPart.startsWith(materialKey)) {
                            material.name = "DielMaterial";
                            material.value = searchPart.mid(materialKey.length());
                            
                            if (!material.value.isEmpty() && material.height > 0) {
                                dielMaterials.append(material);
                            }
                            break;
                        }
                    }
                }
            }
        }
    }
    
    file.close();
    
    // Если не нашли LAYERSET, используем старый метод подсчета
    if (signalLayersetNumber.isEmpty()) {
        qDebug() << "AltiumParser PCB: LAYERSET не найден, используем старый метод подсчета слоев";
        // Убираем слой MultiLayer если он есть (для старого метода)
        if (pcbLayersCount > 0) {
            pcbLayersCount--;
        }
    }
    
    // Итоговое логирование результатов парсинга
    qDebug() << "AltiumParser PCB: === РЕЗУЛЬТАТЫ ПАРСИНГА PCB ===";
    qDebug() << "AltiumParser PCB: Количество слоев:" << pcbLayersCount;
    qDebug() << "AltiumParser PCB: Количество материалов:" << dielMaterials.size();
    
    // Выводим найденные материалы
    for (int i = 0; i < dielMaterials.size(); i++) {
        const DielProperty &material = dielMaterials[i];
        QString typeStr = (material.dielType == 1) ? "ядро" : (material.dielType == 2) ? "препрег" : "неизвестно";
        qDebug() << "AltiumParser PCB: Материал" << i << ":" << material.name << "=" << material.value 
                 << "тип:" << typeStr << "толщина:" << material.height << "мм";
    }
    
    if (pcbLayersCount == 0) {
        qDebug() << "AltiumParser PCB: ПРЕДУПРЕЖДЕНИЕ: Слои не найдены в файле!";
    }
    if (dielMaterials.isEmpty()) {
        qDebug() << "AltiumParser PCB: ПРЕДУПРЕЖДЕНИЕ: Материалы не найдены в файле!";
    }
    
    qDebug() << "AltiumParser PCB: Парсинг платы завершен";
    return true;
}

