const csv = require('csv-parser');
const XLSX = require('xlsx');
const fs = require('fs');
const { Pool } = require('pg');

/**
 * Обработчик файлов CSV/XLSX для загрузки финансовых данных из 1С
 */
class FileProcessor {
  constructor(pool) {
    this.pool = pool;
    this.processingJobs = new Map(); // Хранилище статусов обработки
  }

  /**
   * Обработка файла (CSV или XLSX)
   */
  processFile(filePath, fileType, mapping, reportId) {
    const jobId = `job-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    
    // Инициализируем статус обработки
    this.processingJobs.set(jobId, {
      status: 'processing',
      progress: 0,
      currentStep: 'Начало обработки',
      errors: [],
      warnings: [],
      result: null
    });

    // Запускаем асинхронную обработку (не ждем завершения)
    const processPromise = this._processFileInternal(filePath, fileType, mapping, reportId, jobId);
    
    // Возвращаем jobId и Promise сразу
    return { jobId, processPromise };
  }

  /**
   * Внутренняя обработка файла
   */
  async _processFileInternal(filePath, fileType, mapping, reportId, jobId) {

    try {
      let rows = [];
      
      if (fileType === 'CSV') {
        rows = await this.parseCSV(filePath, jobId);
      } else if (fileType === 'XLSX') {
        rows = await this.parseXLSX(filePath, jobId);
      } else {
        throw new Error(`Неподдерживаемый тип файла: ${fileType}`);
      }

      // Валидация структуры файла
      this.updateJobStatus(jobId, {
        progress: 20,
        currentStep: 'Валидация структуры файла'
      });

      const validationResult = this.validateFileStructure(rows, mapping);
      
      // Добавляем предупреждения из валидации
      if (validationResult.warnings && validationResult.warnings.length > 0) {
        const current = this.processingJobs.get(jobId);
        if (current) {
          if (!current.warnings) {
            current.warnings = [];
          }
          current.warnings.push(...validationResult.warnings);
          this.processingJobs.set(jobId, current);
        }
      }

      if (!validationResult.valid) {
        this.updateJobStatus(jobId, {
          status: 'failed',
          progress: 100,
          errors: validationResult.errors
        });
        return { jobId, success: false, errors: validationResult.errors };
      }

      // Обновляем маппинг с найденными колонками
      if (validationResult.foundColumns && validationResult.foundColumns.length > 0) {
        const updatedMapping = { ...mapping };
        for (const { required, found } of validationResult.foundColumns) {
          if (updatedMapping.columnMappings[required]) {
            updatedMapping.columnMappings[found] = updatedMapping.columnMappings[required];
            // Если названия отличаются, удаляем старое
            if (required !== found) {
              delete updatedMapping.columnMappings[required];
            }
          }
        }
        mapping = updatedMapping;
      }

      // Применение маппинга и преобразование данных
      this.updateJobStatus(jobId, {
        progress: 40,
        currentStep: 'Применение маппинга колонок'
      });

      const mappedData = this.applyMapping(rows, mapping, validationResult.fileColumns);

      // Сохранение в БД
      this.updateJobStatus(jobId, {
        progress: 60,
        currentStep: 'Сохранение данных в базу'
      });

      const saveResult = await this.saveToDatabase(mappedData, reportId, jobId);

      // Финальный статус
      this.updateJobStatus(jobId, {
        status: saveResult.success ? 'completed' : 'partial',
        progress: 100,
        currentStep: 'Обработка завершена',
        result: saveResult
      });

      return {
        success: saveResult.success,
        result: saveResult,
        errors: this.processingJobs.get(jobId).errors
      };

    } catch (error) {
      this.updateJobStatus(jobId, {
        status: 'failed',
        progress: 100,
        currentStep: 'Ошибка обработки',
        errors: [{
          row: 0,
          message: error.message,
          suggestion: 'Проверьте формат файла и повторите попытку'
        }]
      });

      return {
        jobId,
        success: false,
        errors: [{ message: error.message }]
      };
    }
  }

  /**
   * Парсинг CSV файла
   */
  async parseCSV(filePath, jobId) {
    return new Promise((resolve, reject) => {
      const results = [];
      let rowCount = 0;

      fs.createReadStream(filePath)
        .pipe(csv())
        .on('data', (data) => {
          results.push(data);
          rowCount++;
          
          // Обновляем прогресс каждые 100 строк
          if (rowCount % 100 === 0) {
            this.updateJobStatus(jobId, {
              progress: Math.min(15, (rowCount / 1000) * 15),
              currentStep: `Чтение CSV: обработано ${rowCount} строк`
            });
          }
        })
        .on('end', () => {
          this.updateJobStatus(jobId, {
            progress: 15,
            currentStep: `CSV прочитан: ${rowCount} строк`
          });
          resolve(results);
        })
        .on('error', reject);
    });
  }

  /**
   * Парсинг XLSX файла
   */
  async parseXLSX(filePath, jobId) {
    this.updateJobStatus(jobId, {
      progress: 5,
      currentStep: 'Чтение XLSX файла'
    });

    try {
      const workbook = XLSX.readFile(filePath);
      const sheetName = workbook.SheetNames[0]; // Берем первый лист
      const worksheet = workbook.Sheets[sheetName];
      
      // Определяем диапазон данных
      const range = XLSX.utils.decode_range(worksheet['!ref'] || 'A1:Z1000');
      
      // Ключевые слова для поиска строки с заголовками таблицы
      const headerKeywords = [
        'адрес', 'наименование', 'название', 'объект', 'дом', 'здание',
        'сумма', 'доход', 'расход', 'дебет', 'кредит', 'баланс',
        'период', 'дата', 'месяц', 'год',
        'номер', '№', 'код'
      ];
      
      // Ищем строку с заголовками (проверяем первые 30 строк)
      let headerRow = -1;
      let maxMatches = 0;
      
      for (let row = 0; row <= Math.min(range.e.r, 30); row++) {
        let matches = 0;
        const rowValues = [];
        
        // Собираем все значения в строке
        for (let col = range.s.c; col <= Math.min(range.e.c, 20); col++) {
          const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });
          const cell = worksheet[cellAddress];
          if (cell && cell.v) {
            const cellValue = String(cell.v).toLowerCase().trim();
            rowValues.push(cellValue);
            
            // Проверяем, содержит ли значение ключевые слова
            for (const keyword of headerKeywords) {
              if (cellValue.includes(keyword)) {
                matches++;
                break;
              }
            }
          }
        }
        
        // Если в строке найдено достаточно ключевых слов и есть несколько непустых значений
        if (matches >= 2 && rowValues.filter(v => v.length > 0).length >= 3) {
          if (matches > maxMatches) {
            maxMatches = matches;
            headerRow = row;
          }
        }
      }
      
      // Если не нашли строку с заголовками, пробуем найти строку с максимальным количеством непустых ячеек
      if (headerRow === -1) {
        for (let row = 0; row <= Math.min(range.e.r, 20); row++) {
          let nonEmptyCount = 0;
          for (let col = range.s.c; col <= Math.min(range.e.c, 20); col++) {
            const cellAddress = XLSX.utils.encode_cell({ r: row, c: col });
            const cell = worksheet[cellAddress];
            if (cell && cell.v && String(cell.v).trim().length > 0) {
              nonEmptyCount++;
            }
          }
          if (nonEmptyCount >= 4) {
            headerRow = row;
            break;
          }
        }
      }
      
      // Если так и не нашли, используем строку 0 (первую)
      if (headerRow === -1) {
        headerRow = 0;
      }
      
      console.log(`[FileProcessor] Найдена строка заголовков: ${headerRow + 1}`);
      
      // Парсим данные начиная со строки заголовков
      let rows = XLSX.utils.sheet_to_json(worksheet, { 
        range: headerRow,
        defval: '', // Значение по умолчанию для пустых ячеек
        raw: false, // Преобразуем все в строки
        blankrows: false // Пропускаем пустые строки
      });
      
      // Фильтруем пустые строки (где все значения пустые)
      rows = rows.filter(row => {
        const values = Object.values(row);
        return values.some(v => v !== '' && v !== null && v !== undefined);
      });

      // Логируем найденные колонки для отладки
      if (rows.length > 0) {
        const columns = Object.keys(rows[0]);
        console.log(`[FileProcessor] Найдено колонок в XLSX: ${columns.length}`);
        console.log(`[FileProcessor] Колонки: ${columns.join(', ')}`);
        console.log(`[FileProcessor] Первая строка данных:`, rows[0]);
        console.log(`[FileProcessor] Всего строк данных: ${rows.length}`);
      } else {
        console.warn(`[FileProcessor] Не найдено данных в файле после парсинга`);
      }

      this.updateJobStatus(jobId, {
        progress: 15,
        currentStep: `XLSX прочитан: ${rows.length} строк, ${rows.length > 0 ? Object.keys(rows[0]).length : 0} колонок`
      });

      return rows;
    } catch (error) {
      console.error('[FileProcessor] Ошибка парсинга XLSX:', error);
      throw new Error(`Ошибка чтения XLSX файла: ${error.message}`);
    }
  }

  /**
   * Валидация структуры файла
   */
  validateFileStructure(rows, mapping) {
    const errors = [];
    const warnings = [];
    
    if (rows.length === 0) {
      errors.push({
        row: 0,
        message: 'Файл пуст или не содержит данных',
        suggestion: 'Убедитесь, что файл содержит данные и имеет правильный формат'
      });
      return { valid: false, errors, warnings };
    }

    // Получаем колонки из файла
    const firstRow = rows[0];
    const fileColumns = Object.keys(firstRow);
    
    console.log(`[FileProcessor] Валидация: найдено ${fileColumns.length} колонок в файле`);
    console.log(`[FileProcessor] Колонки файла:`, fileColumns);

    // Проверяем наличие обязательных колонок согласно маппингу
    const requiredColumns = Object.keys(mapping.columnMappings || {});
    console.log(`[FileProcessor] Ожидаемые колонки из маппинга:`, requiredColumns);

    // Пробуем найти колонки с похожими названиями (нечувствительно к регистру и пробелам)
    const normalizeColumn = (col) => col.toLowerCase().trim().replace(/\s+/g, ' ');
    const normalizedFileColumns = fileColumns.map(col => ({ original: col, normalized: normalizeColumn(col) }));
    const normalizedRequiredColumns = requiredColumns.map(col => ({ original: col, normalized: normalizeColumn(col) }));

    const missingColumns = [];
    const foundColumns = [];

    for (const reqCol of normalizedRequiredColumns) {
      const found = normalizedFileColumns.find(fc => 
        fc.normalized === reqCol.normalized || 
        fc.normalized.includes(reqCol.normalized) ||
        reqCol.normalized.includes(fc.normalized)
      );
      
      if (found) {
        foundColumns.push({ required: reqCol.original, found: found.original });
      } else {
        missingColumns.push(reqCol.original);
      }
    }

    if (missingColumns.length > 0) {
      warnings.push({
        row: 0,
        message: `Не найдены некоторые колонки: ${missingColumns.join(', ')}`,
        suggestion: `Доступные колонки: ${fileColumns.join(', ')}. Возможно, нужно настроить маппинг.`
      });
    }

    // Проверяем наличие колонки с адресом (для привязки к домам)
    const addressMapping = Object.entries(mapping.columnMappings || {})
      .find(([_, target]) => target === 'address');
    
    let addressColumn = null;
    if (addressMapping) {
      const [reqCol] = addressMapping;
      const normalizedReq = normalizeColumn(reqCol);
      const found = normalizedFileColumns.find(fc => 
        fc.normalized === normalizedReq || 
        fc.normalized.includes(normalizedReq) ||
        normalizedReq.includes(fc.normalized)
      );
      addressColumn = found ? found.original : null;
    }

    // Если не нашли точное совпадение, ищем колонки с похожими названиями (адрес, адр и т.д.)
    if (!addressColumn) {
      const addressKeywords = ['адрес', 'адр', 'address', 'дом', 'здание'];
      const found = normalizedFileColumns.find(fc => 
        addressKeywords.some(keyword => fc.normalized.includes(keyword))
      );
      if (found) {
        addressColumn = found.original;
        warnings.push({
          row: 0,
          message: `Автоматически найдена колонка с адресом: "${found.original}"`,
          suggestion: 'Рекомендуется настроить маппинг для точного соответствия'
        });
      }
    }
    
    if (!addressColumn) {
      errors.push({
        row: 0,
        message: 'Не найдена колонка с адресом дома',
        suggestion: `Доступные колонки: ${fileColumns.join(', ')}. Настройте маппинг для колонки с адресом.`
      });
    }

    return {
      valid: errors.length === 0,
      errors,
      warnings,
      foundColumns,
      fileColumns
    };
  }

  /**
   * Применение маппинга колонок
   */
  applyMapping(rows, mapping, fileColumns = null) {
    const mappedData = [];
    
    // Нормализуем названия колонок для нечеткого поиска
    const normalizeColumn = (col) => col.toLowerCase().trim().replace(/\s+/g, ' ');
    
    // Создаем карту нормализованных колонок файла
    const fileColMap = {};
    if (fileColumns) {
      fileColumns.forEach(col => {
        fileColMap[normalizeColumn(col)] = col;
      });
    } else if (rows.length > 0) {
      Object.keys(rows[0]).forEach(col => {
        fileColMap[normalizeColumn(col)] = col;
      });
    }

    for (let i = 0; i < rows.length; i++) {
      const row = rows[i];
      const mappedRow = {};

      for (const [sourceColumn, targetField] of Object.entries(mapping.columnMappings)) {
        // Пробуем точное совпадение
        let value = row[sourceColumn];
        
        // Если не найдено, пробуем нечеткое совпадение
        if (value === undefined || value === null || value === '') {
          const normalizedSource = normalizeColumn(sourceColumn);
          const foundCol = fileColMap[normalizedSource];
          if (foundCol) {
            value = row[foundCol];
          } else {
            // Пробуем частичное совпадение
            for (const [normCol, origCol] of Object.entries(fileColMap)) {
              if (normCol.includes(normalizedSource) || normalizedSource.includes(normCol)) {
                value = row[origCol];
                break;
              }
            }
          }
        }

        if (value !== undefined && value !== null && value !== '') {
          mappedRow[targetField] = this.parseValue(value, targetField);
        }
      }

      // Добавляем исходную строку для отладки
      mappedRow._sourceRow = i + 1;
      mappedRow._rawData = row;

      mappedData.push(mappedRow);
    }

    return mappedData;
  }

  /**
   * Парсинг значения в зависимости от типа поля
   */
  parseValue(value, fieldName) {
    if (value === null || value === undefined || value === '') {
      return null;
    }

    // Числовые поля
    if (fieldName.includes('amount') || fieldName.includes('income') || 
        fieldName.includes('expense') || fieldName.includes('balance') ||
        fieldName.includes('cost') || fieldName.includes('price')) {
      const num = parseFloat(String(value).replace(/\s/g, '').replace(',', '.'));
      return isNaN(num) ? null : num;
    }

    // Даты
    if (fieldName.includes('date') || fieldName.includes('period')) {
      // Пробуем разные форматы дат
      const date = new Date(value);
      if (!isNaN(date.getTime())) {
        return date.toISOString().split('T')[0];
      }
      return value; // Оставляем как есть, если не удалось распарсить
    }

    // Текстовые поля
    return String(value).trim();
  }

  /**
   * Сохранение данных в базу данных
   */
  async saveToDatabase(mappedData, reportId, jobId) {
    const client = await this.pool.connect();
      let processedRows = 0;
      let errorRows = 0;
      let buildingsFound = 0;

    try {
      await client.query('BEGIN');

      for (let i = 0; i < mappedData.length; i++) {
        const row = mappedData[i];
        const rowNum = row._sourceRow;

        try {
          // Находим дом по адресу (пробуем разные варианты названий полей)
          const address = row.address || row.buildingAddress || row.адрес || row['Адрес'] || 
                         row['адрес дома'] || row['Адрес дома'] || row['Адрес здания'] ||
                         (row._rawData && (row._rawData.address || row._rawData.Адрес || row._rawData['Адрес']));
          
          if (!address || String(address).trim() === '') {
            // Логируем для отладки
            console.log(`[FileProcessor] Строка ${rowNum}: адрес не найден. Доступные поля:`, Object.keys(row));
            this.addError(jobId, {
              row: rowNum,
              message: 'Не указан адрес дома',
              suggestion: `Доступные поля в строке: ${Object.keys(row).filter(k => !k.startsWith('_')).join(', ')}. Убедитесь, что в маппинге указана колонка для адреса.`
            });
            errorRows++;
            continue;
          }
          
          const addressStr = String(address).trim();

          // Ищем дом в БД по адресу
          let buildingResult = await client.query(
            `SELECT id FROM buildings WHERE data->'passport'->>'address' = $1`,
            [addressStr]
          );

          let buildingId;

          // Если дом не найден, пропускаем строку (не создаем автоматически)
          if (buildingResult.rows.length === 0) {
            console.log(`[fileProcessor] ⚠ Дом не найден в базе, пропускаем: "${addressStr}"`);
            // Добавляем в список не найденных адресов
            const current = this.processingJobs.get(jobId);
            if (current) {
              if (!current.notFoundAddresses) {
                current.notFoundAddresses = [];
              }
              if (!current.notFoundAddresses.includes(addressStr)) {
                current.notFoundAddresses.push(addressStr);
              }
              this.processingJobs.set(jobId, current);
            }
            errorRows++;
            continue;
          } else {
            buildingId = buildingResult.rows[0].id;
            buildingsFound++;
          }

      // Определяем период
      const periodStart = row.periodStart || row.period_start || row.startDate || row.date || new Date().toISOString().split('T')[0];
      const periodEnd = row.periodEnd || row.period_end || row.endDate || periodStart;
      const periodType = row.periodType || row.period_type || 'month';
      
      // Логируем для отладки первые несколько строк
      if (i < 3) {
        console.log(`[FileProcessor] Обработка строки ${i + 1}:`, {
          address,
          periodStart,
          totalIncome: row.totalIncome || row.total_income,
          totalExpenses: row.totalExpenses || row.total_expenses,
          balance: row.balance
        });
      }

          // Подготавливаем данные
          const incomeByItems = {};
          const expensesByItems = {};

          // Собираем доходы и расходы по статьям
          for (const [key, value] of Object.entries(row)) {
            if (key.startsWith('income_') && typeof value === 'number') {
              const itemName = key.replace('income_', '').replace(/_/g, ' ');
              incomeByItems[itemName] = (incomeByItems[itemName] || 0) + value;
            } else if (key.startsWith('expense_') && typeof value === 'number') {
              const itemName = key.replace('expense_', '').replace(/_/g, ' ');
              expensesByItems[itemName] = (expensesByItems[itemName] || 0) + value;
            }
          }

          const totalIncome = row.totalIncome || row.total_income || 
            Object.values(incomeByItems).reduce((sum, val) => sum + (val || 0), 0);
          const totalExpenses = row.totalExpenses || row.total_expenses || 
            Object.values(expensesByItems).reduce((sum, val) => sum + (val || 0), 0);
          const balance = row.balance || (totalIncome - totalExpenses);

          // Сохраняем или обновляем данные
          await client.query(
            `INSERT INTO building_financial_data 
             (building_id, report_id, period_start, period_end, period_type, 
              total_income, income_by_items, total_expenses, expenses_by_items, balance, metadata)
             VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
             ON CONFLICT (building_id, period_start, period_end, period_type)
             DO UPDATE SET
               total_income = EXCLUDED.total_income,
               income_by_items = EXCLUDED.income_by_items,
               total_expenses = EXCLUDED.total_expenses,
               expenses_by_items = EXCLUDED.expenses_by_items,
               balance = EXCLUDED.balance,
               metadata = EXCLUDED.metadata,
               updated_at = NOW()`,
            [
              buildingId,
              reportId,
              periodStart,
              periodEnd,
              periodType,
              totalIncome,
              JSON.stringify(incomeByItems),
              totalExpenses,
              JSON.stringify(expensesByItems),
              balance,
              JSON.stringify(row.metadata || {})
            ]
          );

          processedRows++;

          // Обновляем прогресс
          if (i % 10 === 0) {
            const progress = 60 + Math.floor((i / mappedData.length) * 35);
            this.updateJobStatus(jobId, {
              progress,
              currentStep: `Обработано ${i + 1} из ${mappedData.length} строк`
            });
          }

        } catch (error) {
          this.addError(jobId, {
            row: rowNum,
            message: error.message,
            suggestion: 'Проверьте данные в этой строке'
          });
          errorRows++;
        }
      }

      await client.query('COMMIT');

      // Обновляем статус отчета
      if (reportId) {
        const jobStatus = this.processingJobs.get(jobId);
        const notFoundAddresses = jobStatus?.notFoundAddresses || [];
        
        // Формируем error_log с ошибками и не найденными адресами
        const errorLog = {
          errors: jobStatus?.errors || [],
          notFoundAddresses: notFoundAddresses,
          message: notFoundAddresses.length > 0 
            ? `Не найдено ${notFoundAddresses.length} домов из ${mappedData.length}. Данные по этим адресам не были загружены. Создайте дома вручную в системе, затем загрузите отчет повторно.`
            : undefined
        };
        
        await client.query(
          `UPDATE financial_reports 
           SET status = $1, processed_rows = $2, error_rows = $3, error_log = $4
           WHERE id = $5`,
          [
            errorRows === 0 && notFoundAddresses.length === 0 ? 'completed' : (processedRows > 0 ? 'partial' : 'failed'),
            processedRows,
            errorRows + notFoundAddresses.length,
            JSON.stringify(errorLog),
            reportId
          ]
        );
      }

      const jobStatus = this.processingJobs.get(jobId);
      const notFoundAddresses = jobStatus?.notFoundAddresses || [];
      
      return {
        success: processedRows > 0,
        totalRows: mappedData.length,
        processedRows,
        errorRows: errorRows + notFoundAddresses.length,
        buildingsFound,
        buildingsCreated: 0, // Больше не создаем дома автоматически
        notFoundAddresses
      };

    } catch (error) {
      await client.query('ROLLBACK');
      throw error;
    } finally {
      client.release();
    }
  }

  /**
   * Создание нового дома, если его нет в БД
   */
  async createBuildingIfNotExists(client, address, jobId) {
    try {
      // Получаем первый доступный участок (district) для нового дома
      const districtResult = await client.query(
        'SELECT id FROM districts ORDER BY id LIMIT 1'
      );
      
      const districtId = districtResult.rows.length > 0 
        ? districtResult.rows[0].id 
        : 'd-1'; // Дефолтный участок, если нет участков

      // Генерируем ID для нового дома
      const buildingId = `b-auto-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;

      // Создаем минимальную структуру Building
      const newBuilding = {
        id: buildingId,
        districtId: districtId,
        imageUrl: "https://picsum.photos/id/122/800/600",
        nps: 0,
        passport: {
          address: address,
          apartmentsCount: 0,
          general: {
            address: address,
            fiasCode: "",
            constructionYear: new Date().getFullYear(),
            commissionYear: new Date().getFullYear(),
            seriesType: "Не указано",
            floors: 0,
            undergroundFloors: 0,
            totalArea: 0,
            livingArea: 0,
            nonLivingArea: 0,
            commonArea: 0,
            cadastralNumberBuild: "",
            cadastralNumberLand: ""
          },
          construction: {
            foundationType: "",
            foundationMaterial: "",
            wallMaterial: "",
            floorMaterial: "",
            roofType: "",
            roofMaterial: "",
            roofArea: 0,
            facadeType: "",
            facadeInsulation: false,
            windowType: ""
          },
          engineering: {
            heatingType: "",
            heatingWiring: "",
            hasITP: false,
            waterSupplyMaterial: "",
            waterSupplyType: "",
            sewerMaterial: "",
            electricityEntries: 1,
            hasVRU: false,
            gasType: "",
            ventilationType: ""
          },
          meters: [],
          lifts: [],
          land: {
            area: 0,
            hasPlayground: false,
            hasSportsGround: false,
            hasParking: false,
            hasFencing: false,
            hasContainerSite: false
          },
          management: {
            contractDate: "",
            contractNumber: "",
            servicesList: [],
            tariffMaintenance: 0,
            reserveFund: 5.00,
            serviceContracts: []
          }
        },
        staff: [],
        entrances: [],
        commonSections: [],
        accounts: [],
        financials: {
          balance: 0,
          debt: 0,
          collectionRate: 0,
          topDebtors: [],
          invoices: []
        },
        requests: {
          new: 0,
          inProgress: 0,
          overdue: 0
        },
        inspectionHistory: [],
        tasks: [],
        annualPlan: [],
        inventory: [],
        writeOffHistory: [],
        residents: [],
        reports: [],
        isDirty: true
      };

      // Сохраняем новый дом в БД
      await client.query(
        'INSERT INTO buildings (id, data) VALUES ($1, $2)',
        [buildingId, JSON.stringify(newBuilding)]
      );

      // Автоматически создаем опрос NPS для нового дома
      try {
        const existingSurvey = await client.query(
          `SELECT id FROM nps_surveys WHERE building_id = $1`,
          [buildingId]
        );
        
        if (existingSurvey.rows.length === 0) {
          const accessKey = `nps-${buildingId}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
          await client.query(
            `INSERT INTO nps_surveys 
             (building_id, title, description, status, access_key, created_by)
             VALUES ($1, $2, $3, $4, $5, 'system')`,
            [
              buildingId,
              'Опрос удовлетворенности жителей',
              'Помогите нам стать лучше! Поделитесь своим мнением о качестве обслуживания.',
              'draft',
              accessKey
            ]
          );
        }
      } catch (npsErr) {
        console.error(`[fileProcessor] Ошибка создания опроса NPS для дома ${buildingId}:`, npsErr);
      }
      
      // Автоматически создаем отчет для нового дома (текущий месяц) с заполненными данными
      try {
        const now = new Date();
        const currentMonthStart = new Date(now.getFullYear(), now.getMonth(), 1);
        const currentMonthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
        
        const months = [
          'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь',
          'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'
        ];
        const monthName = months[now.getMonth()];
        const reportMonth = `${monthName} ${now.getFullYear()}`;
        
        const existingReport = await client.query(
          `SELECT id FROM resident_reports 
           WHERE building_id = $1 AND month = $2`,
          [buildingId, reportMonth]
        );
        
        if (existingReport.rows.length === 0) {
          // Создаем отчет с начальными данными
          const initialContent = {
            applications: {
              total: 156,
              completed: 153,
              quality: 98
            },
            finances: {
              collected: 2400000,
              expenses: 1890000,
              balance: 560000
            },
            nps: {
              score: 72,
              totalResponses: 45
            }
          };
          
          await client.query(
            `INSERT INTO resident_reports 
             (building_id, month, period_start, period_end, status, content, published_at)
             VALUES ($1, $2, $3, $4, $5, $6::jsonb, NOW())`,
            [
              buildingId,
              reportMonth,
              currentMonthStart.toISOString().split('T')[0],
              currentMonthEnd.toISOString().split('T')[0],
              'published',
              JSON.stringify(initialContent)
            ]
          );
        }
      } catch (reportErr) {
        console.error(`[fileProcessor] Ошибка создания отчета для дома ${buildingId}:`, reportErr);
      }

      // Добавляем информационное сообщение (не ошибку) о создании дома
      const current = this.processingJobs.get(jobId);
      if (current) {
        if (!current.warnings) {
          current.warnings = [];
        }
        current.warnings.push({
          message: `Автоматически создан новый дом: "${address}"`,
          suggestion: 'Рекомендуется заполнить паспорт дома вручную'
        });
        this.processingJobs.set(jobId, current);
      }

      return buildingId;
    } catch (error) {
      console.error('Ошибка создания нового дома:', error);
      this.addError(jobId, {
        row: 0,
        message: `Не удалось создать дом "${address}": ${error.message}`,
        suggestion: 'Проверьте права доступа к БД или создайте дом вручную'
      });
      return null;
    }
  }

  /**
   * Получение статуса обработки
   */
  getJobStatus(jobId) {
    return this.processingJobs.get(jobId) || null;
  }

  /**
   * Обновление статуса обработки
   */
  updateJobStatus(jobId, updates) {
    const current = this.processingJobs.get(jobId);
    if (current) {
      this.processingJobs.set(jobId, { ...current, ...updates });
    }
  }

  /**
   * Добавление ошибки
   */
  addError(jobId, error) {
    const current = this.processingJobs.get(jobId);
    if (current) {
      current.errors.push(error);
      this.processingJobs.set(jobId, current);
    }
  }

  /**
   * Очистка старых заданий (старше 1 часа)
   */
  cleanupOldJobs() {
    const oneHourAgo = Date.now() - 3600000;
    for (const [jobId, job] of this.processingJobs.entries()) {
      if (job.status === 'completed' || job.status === 'failed') {
        // Можно добавить timestamp и удалять старые
        // Пока оставляем все для истории
      }
    }
  }
}

module.exports = FileProcessor;
