const csv = require('csv-parser');
const fs = require('fs');

/**
 * Парсер отчёта по задолженности (CSV с разделителем ;).
 * Строки данных: № п/п (0), Лицевой счёт (1), Ответственный (4), Объект учета (5), Количество месяцев (8), последняя колонка — Общая задолженность.
 */
class DebtorReportProcessor {
  /**
   * Нормализация числа из отчёта: пробелы убрать, запятую заменить на точку.
   */
  parseAmount(str) {
    if (str === undefined || str === null || str === '') return null;
    const s = String(str).replace(/\s/g, '').replace(',', '.').trim();
    if (s === '' || s === '-') return null;
    const n = parseFloat(s);
    return Number.isFinite(n) ? n : null;
  }

  /**
   * Проверка: строка похожа на строку данных (колонка 0 — число, колонка 1 — лицевой счёт вида 00-000000001).
   */
  isDataRow(cells) {
    if (!cells || cells.length < 6) return false;
    const col0 = String(cells[0] || '').trim();
    const col1 = String(cells[1] || '').trim();
    if (col1 === '' || col1.toLowerCase() === 'итого') return false;
    const num0 = parseInt(col0, 10);
    const isNum = col0 !== '' && !Number.isNaN(num0) && num0 >= 1;
    const looksLikeAccount = /^[\d\-]+$/.test(col1) || /^\d{2}-\d{9}$/.test(col1.replace(/\s/g, ''));
    return isNum && (looksLikeAccount || col1.length >= 5);
  }

  /**
   * Парсинг одной строки данных в объект для БД.
   */
  parseDataRow(cells, rowIndex) {
    const account = String(cells[1] || '').trim();
    const responsibleName = String(cells[4] || '').trim();
    const objectAddress = String(cells[5] || '').trim();
    const monthsRaw = String(cells[8] || '').trim();
    const monthsDebt = monthsRaw === '' ? null : (parseInt(monthsRaw, 10) || null);
    const lastCol = cells[cells.length - 1];
    const totalDebt = this.parseAmount(lastCol);
    return {
      row_index: rowIndex,
      account,
      responsible_name: responsibleName,
      object_address: objectAddress,
      months_debt: monthsDebt,
      total_debt: totalDebt != null ? totalDebt : 0,
    };
  }

  /**
   * Парсинг CSV-файла отчёта по задолженности.
   * Возвращает массив объектов { row_index, account, responsible_name, object_address, months_debt, total_debt }.
   */
  async parseDebtorReportCSV(filePath) {
    return new Promise((resolve, reject) => {
      const rows = [];
      let rowIndex = 0;

      fs.createReadStream(filePath, { encoding: 'utf8' })
        .pipe(csv({ separator: ';', headers: false }))
        .on('data', (row) => {
          const cells = Object.values(row);
          if (rowIndex === 0 && cells[0] !== undefined) {
            const first = String(cells[0]).replace(/^\uFEFF/, '');
            cells[0] = first;
          }
          if (this.isDataRow(cells)) {
            rows.push(this.parseDataRow(cells, rowIndex));
          }
          rowIndex++;
        })
        .on('end', () => resolve(rows))
        .on('error', reject);
    });
  }

  /**
   * Парсинг XLSX: чтение первого листа, поиск строк данных по тем же правилам.
   */
  async parseDebtorReportXLSX(filePath) {
    const XLSX = require('xlsx');
    const workbook = XLSX.readFile(filePath);
    const sheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[sheetName];
    const rawData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: '' });
    const rows = [];
    for (let i = 0; i < rawData.length; i++) {
      const cells = rawData[i] || [];
      if (this.isDataRow(cells)) {
        rows.push(this.parseDataRow(cells, i));
      }
    }
    return rows;
  }

  /**
   * Единая точка входа: парсинг по типу файла.
   */
  async parseDebtorReport(filePath, fileType) {
    if (fileType === 'CSV') {
      return this.parseDebtorReportCSV(filePath);
    }
    if (fileType === 'XLSX') {
      return this.parseDebtorReportXLSX(filePath);
    }
    throw new Error('Поддерживаются только CSV и XLSX');
  }
}

module.exports = DebtorReportProcessor;
