const fs = require('node:fs');
const path = require('node:path');

const { GoogleSpreadsheet } = require('google-spreadsheet');
const { JWT } = require('google-auth-library');

function loadServiceAccountCreds({ credsPath, email, privateKey }) {
  const envEmail = (email || '').trim();
  const envKey = (privateKey || '').trim();
  if (envEmail && envKey) {
    return {
      client_email: envEmail,
      private_key: envKey
    };
  }

  const p = path.isAbsolute(credsPath) ? credsPath : path.join(process.cwd(), credsPath);
  if (!fs.existsSync(p)) {
    throw new Error(
      `Файл учётных данных не найден: ${p}\n` +
      'Положи сюда JSON ключ сервис-аккаунта Google (скачай в Google Cloud Console) или задай в .env переменные GOOGLE_SERVICE_ACCOUNT_EMAIL и GOOGLE_PRIVATE_KEY.'
    );
  }
  const raw = fs.readFileSync(p, 'utf8');
  const json = JSON.parse(raw);
  if (!json.client_email || !json.private_key) {
    throw new Error(`Invalid credentials file: ${p}`);
  }
  return json;
}

const DEFAULT_HEADERS = ['Link', 'Price', 'PriceClub', 'UpdatedAt'];

async function ensureSheetHeaders(sheet, headerNames) {
  const needed = headerNames && headerNames.length ? headerNames : DEFAULT_HEADERS;
  const minCols = needed.length;
  if (sheet.columnCount < minCols) {
    await sheet.resize({
      rowCount: Math.max(sheet.rowCount || 1000, 500),
      columnCount: minCols
    });
  }
  let current = [];
  try {
    await sheet.loadHeaderRow();
    current = sheet.headerValues || [];
  } catch (_) {
    current = [];
  }
  const hasAll = needed.every((h) => current.includes(h));
  if (!hasAll || current.length === 0) {
    try {
      await sheet.setHeaderRow(needed);
    } catch (err) {
      const msg = err && err.message ? err.message : String(err);
      if (msg.includes('timed out') || msg.includes('Timeout')) {
        console.warn(
          '[price_searcher] Таймаут при записи заголовков в таблицу (Google API отвечает медленно). Продолжаем; если лист пустой — возможна ошибка дальше. Повторите запуск или проверьте интернет.'
        );
      } else {
        throw err;
      }
    }
  }
}

async function openSpreadsheetAndSheet({
  sheetId,
  sheetTabTitle,
  credsPath,
  email,
  privateKey,
  headerNames
}) {
  const creds = loadServiceAccountCreds({ credsPath, email, privateKey });
  const auth = new JWT({
    email: creds.client_email,
    key: creds.private_key,
    scopes: ['https://www.googleapis.com/auth/spreadsheets']
  });

  const doc = new GoogleSpreadsheet(sheetId, auth);
  await doc.loadInfo();

  const headers = headerNames && headerNames.length ? headerNames : DEFAULT_HEADERS;
  let sheet;

  if (sheetTabTitle && String(sheetTabTitle).trim()) {
    const title = String(sheetTabTitle).trim();
    sheet = doc.sheetsByTitle[title];
    if (!sheet) {
      sheet = await doc.addSheet({ title, headerValues: headers });
    } else {
      await ensureSheetHeaders(sheet, headers);
    }
  } else {
    sheet = doc.sheetsByIndex[0];
    await ensureSheetHeaders(sheet, headers);
  }

  return { doc, sheet };
}

async function getRows(sheet, { offset = 0, limit, sortByColumn, sortOrder = 'asc' } = {}) {
  const opts = {};
  if (offset) opts.offset = offset;
  if (limit != null) opts.limit = limit;
  let rows = await sheet.getRows(opts);
  if (sortByColumn && rows.length > 0) {
    const col = String(sortByColumn).trim();
    if (col) {
      rows = [...rows].sort((a, b) => {
        const va = getRowValue(a, col);
        const vb = getRowValue(b, col);
        const emptyFirst = sortOrder === 'asc';
        const aEmpty = va == null || String(va).trim() === '';
        const bEmpty = vb == null || String(vb).trim() === '';
        if (aEmpty && bEmpty) return 0;
        if (aEmpty) return emptyFirst ? -1 : 1;
        if (bEmpty) return emptyFirst ? 1 : -1;
        const da = new Date(va).getTime();
        const db = new Date(vb).getTime();
        if (Number.isNaN(da) || Number.isNaN(db)) return String(va).localeCompare(String(vb));
        return sortOrder === 'asc' ? da - db : db - da;
      });
    }
  }
  return rows;
}

function getRowValue(row, colName) {
  if (!row) return undefined;
  if (typeof row.get === 'function') return row.get(colName);
  return row[colName];
}

function setRowValue(row, colName, value) {
  if (!row) return;
  if (typeof row.set === 'function') return row.set(colName, value);
  row[colName] = value;
}

async function saveRow(row, dryRun) {
  if (dryRun) return;
  if (row && typeof row.save === 'function') {
    await row.save();
    return;
  }
  throw new Error('Row save() is not available (unexpected google-spreadsheet version?)');
}

module.exports = {
  openSpreadsheetAndSheet,
  getRows,
  getRowValue,
  setRowValue,
  saveRow
};

