#!/usr/bin/env node
/**
 * Headless Playwright чтение остатка НОМЕРОВ в кабинете поставщика crm.bp-gr.ru.
 *
 * У кабинета нет денежного баланса: в шапке выпадашка «Баланс» (js-dropdown,
 * data-toggle="dropdown") с таблицей table.balancetbl. Нужная строка —
 * «Баланс ГЦК» = количество доступных номеров (подтверждено владельцем 28.06).
 * Деньги считаются на стороне PHP: номера × number_price_rub (20 ₽/шт).
 *
 * Логин-флоу — копия refresh-session.js (Yii2 LoginForm).
 *
 * Input (JSON через stdin):  {login, password, url}
 * Output (JSON через stdout): {numbers: <int>}
 *
 * Exit codes:
 *   0 — success (число номеров найдено)
 *   1 — auth failed (логин/пароль отклонены)
 *   2 — строка «Баланс ГЦК» не найдена (разметка кабинета изменилась)
 *   3 — timeout (60s)
 *   4 — invalid input или другая ошибка
 */
const { chromium } = require('playwright');

const TIMEOUT_MS = 60_000;

async function readNumbers(args) {
    let browser = null;
    try {
        browser = await chromium.launch({ headless: true });
        const context = await browser.newContext();
        const page = await context.newPage();

        await page.goto(args.url, { waitUntil: 'load', timeout: TIMEOUT_MS });

        const loginSelector = '#loginform-username';
        await page.fill(loginSelector, args.login);
        await page.fill('#loginform-password', args.password);
        await page.click('button[type=submit]');
        await page
            .waitForFunction((sel) => !document.querySelector(sel), loginSelector, { timeout: TIMEOUT_MS })
            .catch(() => {});
        await page.waitForLoadState('networkidle', { timeout: TIMEOUT_MS }).catch(() => {});

        if ((await page.locator(loginSelector).count()) > 0) {
            process.stderr.write(JSON.stringify({ error: 'login rejected: still on login page after submit' }));
            process.exit(1);
        }

        // Раскрыть выпадашку «Баланс» (js-dropdown в шапке), затем прочитать table.balancetbl.
        await page.getByText('Баланс', { exact: true }).first().click().catch(() => {});
        await page.waitForTimeout(1500);

        // Найти в таблице баланса строку «Баланс ГЦК» и извлечь число.
        const numbers = await page.evaluate(() => {
            const rows = Array.from(document.querySelectorAll('table.balancetbl tr'));
            for (const tr of rows) {
                const cells = tr.querySelectorAll('td');
                if (cells.length >= 2 && /Баланс\s*ГЦК/i.test(cells[0].textContent || '')) {
                    const raw = (cells[1].textContent || '').replace(/[^\d-]/g, '');
                    const n = parseInt(raw, 10);
                    return Number.isFinite(n) ? n : null;
                }
            }
            return null;
        });

        if (numbers === null) {
            process.stderr.write(JSON.stringify({ error: 'строка «Баланс ГЦК» не найдена (разметка кабинета изменилась)' }));
            process.exit(2);
        }

        process.stdout.write(JSON.stringify({ numbers }));
        process.exit(0);
    } catch (err) {
        process.stderr.write(JSON.stringify({ error: err.message }));
        process.exit(err.message && err.message.includes('Timeout') ? 3 : 4);
    } finally {
        if (browser) {
            await browser.close();
        }
    }
}

let input = '';
process.stdin.on('data', (chunk) => { input += chunk; });
process.stdin.on('end', () => {
    let args;
    try {
        args = JSON.parse(input);
    } catch (e) {
        process.stderr.write(JSON.stringify({ error: 'invalid JSON on stdin' }));
        process.exit(4);
    }
    if (!args.login || !args.password || !args.url) {
        process.stderr.write(JSON.stringify({ error: 'missing required keys: login, password, url' }));
        process.exit(4);
    }
    readNumbers(args).catch((err) => {
        const message = err && err.message ? err.message : String(err);
        process.stderr.write(JSON.stringify({ error: message }));
        process.exit(4);
    });
});
