/**
 * batch.js -- multi-device aware
 *
 * Usage (called by bridge.js automatically):
 *   node batch.js --device <adb-device-id> --token <jwt> 0711... 0722... 0733...
 *   node batch.js --device <adb-device-id> --token <jwt> --file phones.txt
 */

import { execSync } from 'child_process';
import fs from 'fs';
import os from 'os';
import path from 'path';

function sleep(seconds) {
    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, Math.round(seconds * 1000));
}

// -- Parse args ----------------------------------------------------------------
const args = process.argv.slice(2);

function getFlag(flag) {
    const i = args.indexOf(flag);
    return i !== -1 ? args[i + 1] : null;
}

const DEVICE_ID = getFlag('--device');
const TOKEN     = getFlag('--token');
const BATCH_ID  = getFlag('--batch-id') ? parseInt(getFlag('--batch-id')) : null;

if (!DEVICE_ID) { console.error('ERROR: --device <adb-serial> is required'); process.exit(1); }
if (!TOKEN)     { console.error('ERROR: --token <jwt> is required');          process.exit(1); }

const cleanArgs = [];
for (let i = 0; i < args.length; i++) {
    if (['--device','--token','--file','--batch-id'].includes(args[i])) { i++; continue; }
    cleanArgs.push(args[i]);
}

const fileArg = getFlag('--file');
let phones = fileArg
    ? fs.readFileSync(fileArg, 'utf8').trim().split('\n').map(p => p.trim()).filter(Boolean)
    : cleanArgs.filter(Boolean);

if (!phones.length) { console.error('No phone numbers provided.'); process.exit(1); }

// -- Config -------------------------------------------------------------------
const BACKEND           = (process.env.BACKEND_URL || 'https://thibitisha.xyz/api').trim();
const AIRTEL_PACKAGE    = 'com.airtel.africa.selfcare';
const RECIPIENT_FIELD_X = 540;
const RECIPIENT_FIELD_Y = 1076;

console.log(`\n[${DEVICE_ID}] Verifying ${phones.length} number(s)...\n`);

// -- ADB helpers --------------------------------------------------------------
function adb(cmd) {
    return execSync(`adb -s ${DEVICE_ID} shell ${cmd}`, { encoding: 'utf8' }).trim();
}

// -- UI dump ------------------------------------------------------------------
const SAFE_ID = DEVICE_ID.replace(/[^a-z0-9]/gi, '_');
const TMP_XML = path.join(os.tmpdir(), `ui_${SAFE_ID}.xml`);

function dumpXml() {
    adb(`uiautomator dump /sdcard/ui_${SAFE_ID}.xml`);
    execSync(`adb -s ${DEVICE_ID} pull /sdcard/ui_${SAFE_ID}.xml "${TMP_XML}"`, { encoding: 'utf8' });
    return fs.readFileSync(TMP_XML, 'utf8');
}

// -- Poll UI until matchFn returns truthy or timeout --------------------------
function pollUI(matchFn, timeoutMs = 8000, intervalMs = 350) {
    const deadline = Date.now() + timeoutMs;
    while (Date.now() < deadline) {
        try {
            const result = matchFn(dumpXml());
            if (result) return result;
        } catch { /* device busy, retry */ }
        sleep(intervalMs / 1000);
    }
    return null;
}

// -- App state: true when already on the Send Money screen --------------------
let appReady = false;

function ensureOnSendMoneyScreen() {
    if (appReady) return;

    adb('input keyevent 4');
    sleep(0.3);
    adb('input keyevent 4');
    sleep(0.3);

    adb(`am start -n ${AIRTEL_PACKAGE}/com.airtel.africa.selfcare.feature.login.activity.LoginActivity`);

    // Wait for Send Money button to appear (replaces sleep(3))
    const btn = pollUI(xml => {
        const m = xml.match(/text="Send Money[^"]*"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
        return m ? { x: Math.floor((+m[1] + +m[3]) / 2), y: Math.floor((+m[2] + +m[4]) / 2) } : null;
    }, 10000, 400);

    if (!btn) throw new Error('Send Money button not found - app may not be logged in');
    adb(`input tap ${btn.x} ${btn.y}`);

    // Wait for input field to be ready (replaces sleep(2))
    const ready = pollUI(xml => xml.includes('com.airtel.africa.selfcare:id/'), 6000, 300);
    if (!ready) throw new Error('Send Money screen did not load');

    appReady = true;
}

// -- Clear the recipient input field ------------------------------------------
function clearField() {
    adb(`input tap ${RECIPIENT_FIELD_X} ${RECIPIENT_FIELD_Y}`);
    sleep(0.2);
    adb('input keyevent KEYCODE_MOVE_END');
    sleep(0.1);
    // All 15 DEL keycodes in one adb call instead of 15 separate execSync calls
    execSync(`adb -s ${DEVICE_ID} shell input keyevent 67 67 67 67 67 67 67 67 67 67 67 67 67 67 67`, { encoding: 'utf8' });
}

// -- Scrape recipient name ----------------------------------------------------
function scrapeName(phoneNumber) {
    ensureOnSendMoneyScreen();

    clearField();
    adb(`input text "${phoneNumber}"`);

    // Small pause so app clears old recipient name before polling starts
    sleep(0.5);

    // Poll for name instead of fixed sleep(4)
    const name = pollUI(xml => {
        const m1 = xml.match(/resource-id="com\.airtel\.africa\.selfcare:id\/recipient_name"[^>]*text="([^"]+)"/);
        const m2 = xml.match(/text="([^"]+)"[^>]*resource-id="com\.airtel\.africa\.selfcare:id\/recipient_name"/);
        const v = (m1?.[1] || m2?.[1] || '').trim();
        return v || null;
    }, 8000, 350);

    return name;
}

// -- Main loop ----------------------------------------------------------------
let matched = 0, mismatch = 0, unknown = 0, failed = 0;
const results = [];

for (let i = 0; i < phones.length; i++) {
    const phone = phones[i];
    process.stdout.write(`[${DEVICE_ID}] [${i + 1}/${phones.length}] ${phone} -> `);

    let scrapedName = null;
    try {
        scrapedName = scrapeName(phone);
    } catch (err) {
        console.log(`SCRAPE FAILED: ${err.message} -> reporting as unknown`);
        appReady = false;
        failed++;
        try {
            const r = await fetch(`${BACKEND}/verify`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TOKEN}` },
                body: JSON.stringify({ phone, scraped_name: null, device_id: DEVICE_ID, batch_id: BATCH_ID }),
            });
            if (!r.ok) console.log(`[${DEVICE_ID}] backend report failed: HTTP ${r.status}`);
        } catch (e) { console.log(`[${DEVICE_ID}] backend report failed: ${e.message}`); }
        results.push({ phone, status: 'unknown', device_id: DEVICE_ID });
        continue;
    }

    if (!scrapedName) {
        console.log('NAME NOT FOUND (not on Airtel Money) -> reporting as unknown');
        failed++;
        try {
            const r = await fetch(`${BACKEND}/verify`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TOKEN}` },
                body: JSON.stringify({ phone, scraped_name: null, device_id: DEVICE_ID, batch_id: BATCH_ID }),
            });
            if (!r.ok) console.log(`[${DEVICE_ID}] backend report failed: HTTP ${r.status}`);
        } catch (e) { console.log(`[${DEVICE_ID}] backend report failed: ${e.message}`); }
        results.push({ phone, status: 'unknown', device_id: DEVICE_ID });
        continue;
    }

    process.stdout.write(`"${scrapedName}" -> `);

    let result;
    try {
        const resp = await fetch(`${BACKEND}/verify`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TOKEN}` },
            body: JSON.stringify({ phone, scraped_name: scrapedName, device_id: DEVICE_ID, batch_id: BATCH_ID }),
        });
        if (!resp.ok) {
            const body = await resp.text();
            let detail;
            try { detail = JSON.parse(body).detail || `HTTP ${resp.status}`; } catch { detail = `HTTP ${resp.status}`; }
            throw new Error(detail);
        }
        result = await resp.json();
    } catch (err) {
        console.log(`BACKEND FAILED: ${err.message}`);
        failed++;
        results.push({ phone, scraped_name: scrapedName, status: 'backend_failed', device_id: DEVICE_ID });
        continue;
    }

    if (result.status === 'matched')  { matched++;  console.log(`MATCHED (score: ${result.score})`); }
    if (result.status === 'mismatch') { mismatch++; console.log(`MISMATCH - expected "${result.full_name}" (score: ${result.score})`); }
    if (result.status === 'unknown')  { unknown++;  console.log('UNKNOWN - not in your records'); }

    results.push({
        phone,
        scraped_name:  scrapedName,
        expected_name: result.full_name,
        status:        result.status,
        score:         result.score,
        date_of_birth: result.date_of_birth || null,
        device_id:     DEVICE_ID,
    });
}

// Return phone to home
try { execSync(`adb -s ${DEVICE_ID} shell input keyevent 3`); } catch { /* ignore */ }

// Summary
console.log(`\n[${DEVICE_ID}] -- Summary --------------------------`);
console.log(`  Total:    ${phones.length}`);
console.log(`  Matched:  ${matched}`);
console.log(`  Mismatch: ${mismatch}`);
console.log(`  Unknown:  ${unknown}`);
console.log(`  Failed:   ${failed}`);

const outFile = `results_${DEVICE_ID.replace(/[^a-z0-9]/gi, '_')}_${Date.now()}.json`;
fs.writeFileSync(outFile, JSON.stringify(results, null, 2));
console.log(`  Saved to: ${outFile}\n`);
