#!/usr/bin/env node
const fs = require('fs/promises');
const path = require('path');
const { chromium } = require('playwright-core');

const DIA_DNI = process.env.DIA_DNI || '';
const DIA_EMAIL = process.env.DIA_EMAIL || '';
const DIA_PASSWORD = process.env.DIA_PASSWORD || '';

const OUT_DIR = path.join(__dirname, 'data');
const OUT_FILE = path.join(OUT_DIR, 'dia_orders_result.json');

function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function clickIfExists(page, selectors, timeout = 1200) {
  for (const sel of selectors) {
    const loc = page.locator(sel).first();
    if (await loc.count()) {
      try {
        await loc.click({ timeout });
        return true;
      } catch {}
    }
  }
  return false;
}

async function typeAt(page, x, y, text) {
  await page.mouse.click(x, y);
  await wait(120);
  await page.keyboard.type(text, { delay: 20 });
}

function extractOrderIds(payload) {
  const ids = [];
  const seen = new Set();

  function push(v) {
    if (v === undefined || v === null) return;
    const s = String(v).trim();
    if (!s || seen.has(s)) return;
    seen.add(s);
    ids.push(s);
  }

  function walk(node) {
    if (!node || typeof node !== 'object') return;
    if (Array.isArray(node)) {
      for (const n of node) walk(n);
      return;
    }

    if ('orderId' in node) push(node.orderId);
    if ('order_id' in node) push(node.order_id);
    if ('id' in node && (typeof node.id === 'string' || typeof node.id === 'number')) {
      if ('creationDate' in node || 'status' in node || 'value' in node || 'items' in node) push(node.id);
    }

    for (const v of Object.values(node)) walk(v);
  }

  walk(payload);
  return ids;
}

function summarizeCookies(cookies) {
  const byDomain = {};
  for (const c of cookies) {
    const d = c.domain || 'unknown';
    byDomain[d] = byDomain[d] || { count: 0, names: [] };
    byDomain[d].count += 1;
    if (!byDomain[d].names.includes(c.name)) byDomain[d].names.push(c.name);
  }
  return byDomain;
}

(async () => {
  if (!DIA_DNI || !DIA_EMAIL || !DIA_PASSWORD) {
    throw new Error('Missing DIA_DNI / DIA_EMAIL / DIA_PASSWORD env vars');
  }

  await fs.mkdir(OUT_DIR, { recursive: true });

  const browser = await chromium.launch({
    headless: process.env.HEADFUL === '1' ? false : true,
    executablePath: '/usr/bin/chromium-browser',
    args: ['--no-sandbox', '--disable-dev-shm-usage', '--disable-popup-blocking'],
  });

  const context = await browser.newContext({
    viewport: { width: 1350, height: 945 },
    locale: 'es-AR',
    extraHTTPHeaders: { 'Accept-Language': 'es-AR,es;q=0.9,en;q=0.8' },
  });

  await context.tracing.start({ screenshots: true, snapshots: true, sources: true });
  const page = await context.newPage();

  const net = [];
  context.on('response', (res) => {
    try {
      const url = res.url();
      console.log('NET_TRACE:', res.request().method(), url, res.status());
      if (url.includes('login') || url.includes('check-user') || url.includes('validate')) {
        console.log('HEADERS_TRACE:', url, JSON.stringify(res.request().headers()));
        res.request().postDataJSON ? res.request().postDataJSON() : res.request().postData();
      }
      if (!/diaonline|diadigital|auth|vtex|oms|order|orders|login|account/i.test(url)) return;
      const status = res.status();
      const location = res.headers()['location'] || null;
      net.push({
        status,
        method: res.request().method(),
        url,
        location,
      });
      if (net.length > 300) net.shift();
    } catch {}
  });

  let authenticated = false;
  let finalEndpoint = null;
  let finalStatus = null;
  let ordersCount = 0;
  let sampleOrderIds = [];

  try {
    await page.goto('https://diaonline.supermercadosdia.com.ar/login?returnUrl=%2Faccount%23%2Fmy-orders', {
      waitUntil: 'domcontentloaded',
      timeout: 90000,
    });

    await wait(1800);

    const dniDigits = String(DIA_DNI).replace(/\D/g, '');
    const dniMask = dniDigits.length === 8
      ? `${dniDigits[0]}.${dniDigits.slice(1, 4)}.${dniDigits.slice(4)}`
      : DIA_DNI;

    const popupPromise = context.waitForEvent('page', { timeout: 8000 }).catch(() => null);

    let clickedLogin = false;

    clickedLogin = await clickIfExists(page, [
      'button:visible:has-text("Entrar conMi Cuenta o Registrarme")',
      'button:visible:has-text("Entrar con Mi Cuenta o Registrarme")',
      'button:visible:has-text("ENTRAR CONMI CUENTA O REGISTRARME")',
    ], 10000);

    if (!clickedLogin) {
      try {
        const recLoc = page.locator('div:nth-of-type(6) li:nth-of-type(3) div > span:visible').first();
        if (await recLoc.count()) {
          await recLoc.click({ timeout: 3500, offset: { x: 173.5, y: 18.5625 } });
          clickedLogin = true;
        }
      } catch {}
    }

    let authPage = await popupPromise;
    if (!authPage) {
      await wait(1200);
      authPage = page;
    }

    await authPage.waitForLoadState('domcontentloaded', { timeout: 30000 }).catch(() => {});
    await wait(1000);

    if (!/auth\.diadigital\.app/i.test(authPage.url())) {
      await authPage.goto('https://auth.diadigital.app/#login-email-document-page', {
        waitUntil: 'domcontentloaded',
        timeout: 90000,
      });
      await wait(1200);
    }

    await authPage.evaluate(() => {
      const candidate = Array.from(document.querySelectorAll('flt-semantics-placeholder, flt-semantics, button, [role="button"]'))
        .find((n) => /enable accessibility/i.test((n.innerText || n.textContent || '').trim()));
      if (candidate) candidate.click();
    }).catch(() => {});

    await wait(700);

    const inputCount1 = await authPage.locator('input').count().catch(() => 0);
    if (inputCount1 >= 2) {
      const i0 = authPage.locator('input').nth(0);
      const i1 = authPage.locator('input').nth(1);
      await i0.fill(dniMask).catch(async () => i0.fill(dniDigits).catch(() => {}));
      await i1.fill(DIA_EMAIL).catch(() => {});
    } else {
      await typeAt(authPage, 126, 223, dniMask);
      await typeAt(authPage, 125, 299, DIA_EMAIL);
    }

    await clickIfExists(authPage, ['button:has-text("Continuar")', 'flt-semantics:has-text("Continuar")'], 1200).catch(() => {});
    await authPage.mouse.click(399, 405).catch(() => {});

    await wait(2600);

    const inputCount2 = await authPage.locator('input').count().catch(() => 0);
    if (inputCount2 >= 1) {
      const passInput = authPage.locator('input[type="password"], input').first();
      await passInput.fill(DIA_PASSWORD).catch(async () => {
        await typeAt(authPage, 128, 223, DIA_PASSWORD);
      });
    } else {
      await typeAt(authPage, 128, 223, DIA_PASSWORD);
    }

    await clickIfExists(authPage, ['button:has-text("Continuar")', 'flt-semantics:has-text("Continuar")'], 1200).catch(() => {});
    await authPage.mouse.click(400, 361).catch(() => {});

    await wait(7000);

    const storePage = (!authPage.isClosed() && /diaonline\.supermercadosdia\.com\.ar/i.test(authPage.url())) ? authPage : page;

    // Recorder semantics: do an extra storefront login trigger click and wait for potential nav.
    if (!storePage.isClosed()) {
      try {
        const navPromise = storePage.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 12000 }).catch(() => null);
        await clickIfExists(storePage, [
          'div:nth-of-type(6) li:nth-of-type(3) div > span',
          'button:has-text("Entrar con Mi Cuenta o Registrarme")',
          'button:has-text("Entrar conMi Cuenta o Registrarme")',
        ], 2500);
        await navPromise;
      } catch {}
      await wait(1800);
    }

    await storePage.goto('https://diaonline.supermercadosdia.com.ar/account#/my-orders', {
      waitUntil: 'domcontentloaded',
      timeout: 90000,
    }).catch(() => {});

    await wait(4500);

    const candidateEndpoints = [
      'https://diaonline.supermercadosdia.com.ar/api/oms/user/orders/?page=1&includeProfileLastPurchases=true',
      'https://diaonline.supermercadosdia.com.ar/api/oms/user/orders?page=1&per_page=50',
      'https://diaonline.supermercadosdia.com.ar/api/oms/user/orders?page=1',
    ];

    for (const endpoint of candidateEndpoints) {
      const req = await context.request.get(endpoint, {
        timeout: 30000,
        headers: { accept: 'application/json, text/plain, */*' },
      }).catch((e) => ({
        ok: () => false,
        status: () => 0,
        text: async () => String(e && e.message ? e.message : e),
        headers: () => ({}),
      }));

      const status = req.status();
      const text = await req.text();
      const ct = (req.headers()['content-type'] || '').toLowerCase();
      let json = null;
      if (ct.includes('application/json') || text.startsWith('{') || text.startsWith('[')) {
        try { json = JSON.parse(text); } catch {}
      }

      finalEndpoint = endpoint;
      finalStatus = status;

      if (req.ok() && json && typeof json === 'object') {
        const root = json;
        const arr = Array.isArray(root?.list)
          ? root.list
          : Array.isArray(root?.orders)
            ? root.orders
            : Array.isArray(root)
              ? root
              : [];

        const ids = extractOrderIds(root);
        ordersCount = arr.length || ids.length;
        sampleOrderIds = ids.slice(0, 5);
        authenticated = true;
        break;
      }
    }

    const cookies = await context.cookies().catch(() => []);
    const redirectChain = net
      .filter((x) => x.status >= 300 && x.status < 400)
      .slice(-40)
      .map((x) => ({ status: x.status, url: x.url, location: x.location }));

    const output = {
      generatedAt: new Date().toISOString(),
      authenticated,
      ordersCount,
      endpoint: finalEndpoint,
      status: finalStatus,
      sampleOrderIds,
      diagnostics: {
        finalPageUrl: storePage.url(),
        cookieSummary: summarizeCookies(cookies),
        redirectChain,
        networkTail: net.slice(-80),
      },
    };

    await fs.writeFile(OUT_FILE, JSON.stringify(output, null, 2));

    console.log('saved', OUT_FILE);
    console.log('authenticated', authenticated, 'status', finalStatus, 'ordersCount', ordersCount);
  } catch (err) {
    const cookies = await context.cookies().catch(() => []);
    const output = {
      generatedAt: new Date().toISOString(),
      authenticated: false,
      ordersCount: 0,
      endpoint: finalEndpoint,
      status: finalStatus,
      sampleOrderIds: [],
      diagnostics: {
        finalPageUrl: page.url(),
        cookieSummary: summarizeCookies(cookies),
        redirectChain: net.filter((x) => x.status >= 300 && x.status < 400).slice(-40),
        networkTail: net.slice(-80),
        error: String(err && err.message ? err.message : err),
      },
    };
    await fs.writeFile(OUT_FILE, JSON.stringify(output, null, 2));
    console.error('run_failed', String(err && err.message ? err.message : err));
    process.exitCode = 1;
  } finally {
    await context.tracing.stop({ path: path.join(OUT_DIR, 'trace.zip') }).catch(() => {});
    await browser.close().catch(() => {});
  }
})();
