/**
 * 店小秘全自动登录 v8
 * 浏览器方案：稳定性修复
 * - domcontentloaded 替代 networkidle
 * - 等 jQuery 就绪后再操作
 * - waitForResponse 确保 API 触发
 * - 捕获请求体调试
 */
import { chromium } from 'playwright';
import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';
import { execSync } from 'child_process';
import sharp from 'sharp';

const COOKIE_FILE = './cookies.json';
const SCREENSHOTS_DIR = './screenshots';
const DOWNLOAD_DIR = './downloads';
const MAX_RETRIES = 20;

mkdirSync(SCREENSHOTS_DIR, { recursive: true });
mkdirSync(DOWNLOAD_DIR, { recursive: true });

async function ocrCaptcha(imagePath) {
  const presets = [
    async (s, d) => sharp(s).grayscale().resize({ width: 468 }).normalize().sharpen({ sigma: 1.5 }).threshold(130).toFile(d),
    async (s, d) => sharp(s).grayscale().resize({ width: 468 }).normalize().threshold(100).toFile(d),
    async (s, d) => sharp(s).grayscale().resize({ width: 468 }).normalize().threshold(160).toFile(d),
    async (s, d) => sharp(s).resize({ width: 468 }).toFile(d),
    async (s, d) => sharp(s).grayscale().resize({ width: 468 }).negate().normalize().threshold(128).toFile(d),
    async (s, d) => sharp(s).grayscale().resize({ width: 600 }).normalize().sharpen({ sigma: 3 }).threshold(120).toFile(d),
  ];

  for (let i = 0; i < presets.length; i++) {
    const p = `${SCREENSHOTS_DIR}/cap_p${i}.png`;
    try { await presets[i](imagePath, p); } catch { continue; }
    for (const psm of ['7', '8']) {
      try {
        const r = execSync(
          `tesseract "${p}" stdout --psm ${psm} -c tessedit_char_whitelist=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`,
          { encoding: 'utf-8', timeout: 10000 }
        ).trim().replace(/[\s\n\r]/g, '');
        if (r && r.length === 4) return r;
      } catch {}
    }
  }
  for (let i = 0; i < presets.length; i++) {
    const p = `${SCREENSHOTS_DIR}/cap_p${i}.png`;
    if (!existsSync(p)) continue;
    try {
      const r = execSync(
        `tesseract "${p}" stdout --psm 7 -c tessedit_char_whitelist=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`,
        { encoding: 'utf-8', timeout: 10000 }
      ).trim().replace(/[\s\n\r]/g, '');
      if (r && r.length >= 3) return r.substring(0, 4);
    } catch {}
  }
  return null;
}

async function main() {
  console.log('====== 店小秘全自动登录 v8 ======\n');

  const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
  const context = await browser.newContext({
    viewport: { width: 1920, height: 1080 },
    locale: 'zh-CN',
    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
  });
  const page = await context.newPage();

  // 监听请求体（调试用）
  page.on('request', req => {
    if (req.url().includes('userLoginNew2')) {
      console.log(`  [REQ] ${req.method()} ${req.url()}`);
      console.log(`  [REQ body] ${req.postData()?.substring(0, 500)}`);
    }
  });

  page.on('response', async resp => {
    if (resp.url().includes('userLoginNew2')) {
      try {
        const body = await resp.text();
        console.log(`  [RESP] ${resp.status()} ${body.substring(0, 300)}`);
      } catch {}
    }
  });

  for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
    console.log(`\n>> ===== 第 ${attempt}/${MAX_RETRIES} 次 =====`);

    // 每次完整刷新
    try {
      await page.goto('https://www.dianxiaomi.com/home.htm', {
        waitUntil: 'domcontentloaded',
        timeout: 20000,
      });
    } catch (e) {
      console.log(`  页面加载失败: ${e.message}`);
      continue;
    }

    // 等待 jQuery 和登录表单就绪
    try {
      await page.waitForFunction(() => {
        return typeof $ !== 'undefined' &&
               document.getElementById('exampleInputName') &&
               document.getElementById('verifyImgCode') &&
               typeof login === 'function';
      }, { timeout: 10000 });
    } catch {
      console.log('  JS 未就绪');
      continue;
    }

    // 等验证码图片加载
    await page.waitForTimeout(2000);

    // 截图验证码
    const captchaEl = await page.$('#verifyImgCode');
    if (!captchaEl) { console.log('  验证码元素不存在'); continue; }

    const rawPath = `${SCREENSHOTS_DIR}/captcha_raw.png`;
    await captchaEl.screenshot({ path: rawPath });

    // OCR
    const code = await ocrCaptcha(rawPath);
    if (!code) { console.log('  OCR 失败'); continue; }
    console.log(`  验证码: "${code}"`);

    // 用 jQuery 设值（login() 用 $.trim($('#xxx').val()) 读取）
    await page.evaluate((c) => {
      $('#exampleInputName').val('MiLe-kf01');
      $('#exampleInputPassword').val('Vxdas@302');
      $('#verifyCode').val(c);
    }, code);

    // 确认
    const vals = await page.evaluate(() => ({
      a: $.trim($('#exampleInputName').val()),
      p: $.trim($('#exampleInputPassword').val()) ? '***' : 'empty',
      c: $.trim($('#verifyCode').val()),
    }));
    console.log(`  值确认: ${JSON.stringify(vals)}`);

    // 设置 waitForResponse
    const respPromise = page.waitForResponse(
      r => r.url().includes('userLoginNew2.json'),
      { timeout: 15000 }
    ).catch(() => null);

    // 直接调用 login() 函数
    console.log('  调用 login()...');
    const loginResult = await page.evaluate(() => {
      try {
        login();
        return 'called';
      } catch (e) {
        return 'error: ' + e.message;
      }
    });
    console.log(`  login() 返回: ${loginResult}`);

    // 等待 API 响应
    const resp = await respPromise;

    if (resp) {
      let data;
      try {
        data = await resp.json();
      } catch {
        console.log('  响应非JSON');
        continue;
      }

      console.log(`  结果: ${JSON.stringify(data)}`);

      if (data.code === 0 || (data.url && data.url.length > 1 && !data.error)) {
        console.log('\n>> ★★★ 登录成功！★★★');

        // 等页面跳转
        await page.waitForTimeout(3000);
        console.log('>> 跳转后 URL:', page.url());

        if (page.url().includes('/home.htm') || page.url().includes('/index.htm')) {
          const target = data.url?.startsWith('/') ? `https://www.dianxiaomi.com${data.url}` : 'https://www.dianxiaomi.com/saleManage/index.htm';
          await page.goto(target, { waitUntil: 'domcontentloaded', timeout: 20000 }).catch(() => {});
        }

        const cookies = await context.cookies();
        writeFileSync(COOKIE_FILE, JSON.stringify(cookies, null, 2));
        console.log(`>> Cookie 已保存（${cookies.length} 条）`);

        return { success: true, page, context, browser };
      }

      const err = data.error || '';
      console.log(`  错误: ${err}`);

      if (err.includes('密码错误') || err.includes('不存在') || err.includes('锁定')) {
        console.log('>> 严重错误，停止');
        break;
      }
    } else {
      console.log('  无 API 响应（超时）');
    }
  }

  await page.screenshot({ path: `${SCREENSHOTS_DIR}/final-fail.png`, fullPage: true }).catch(() => {});
  await browser.close();
  return { success: false };
}

async function explore(page) {
  console.log('\n>> ===== 探索后台 =====');
  console.log(`>> URL: ${page.url()}`);
  console.log(`>> 标题: ${await page.title()}`);

  await page.screenshot({ path: `${SCREENSHOTS_DIR}/backend-main.png`, fullPage: true });

  const text = await page.evaluate(() => document.body?.innerText?.substring(0, 8000));
  console.log('>> 页面文本:\n', text);

  const links = await page.$$eval('a', els =>
    els.map(el => ({ text: el.textContent.trim().replace(/\s+/g, ' ').substring(0, 60), href: el.href }))
    .filter(e => e.text && e.href?.includes('dianxiaomi'))
    .filter((e, i, arr) => arr.findIndex(a => a.href === e.href) === i)
  );
  console.log(`\n>> 链接（${links.length} 个）：`);
  for (const l of links) {
    const star = ['采购', '仓库', '导出', '库存', '备货', '建议'].some(k => l.text.includes(k)) ? '★' : ' ';
    console.log(`  ${star} [${l.text}] ${l.href}`);
  }

  for (const p of ['/saleManage/index.htm', '/purchaseManage/purchaseSuggestion.htm', '/purchaseManage/purchaseOrder.htm', '/stockManage/stockList.htm']) {
    try {
      await page.goto(`https://www.dianxiaomi.com${p}`, { waitUntil: 'domcontentloaded', timeout: 15000 });
      const t = await page.title();
      const ok = !t.includes('Error') && !page.url().includes('/home.htm');
      console.log(`\n  ${ok ? '✓' : '✗'} ${p} [${t}]`);
      if (ok) {
        await page.screenshot({ path: `${SCREENSHOTS_DIR}/page${p.replace(/\//g, '_')}.png`, fullPage: true });
        const btns = await page.$$eval('button, a.btn, .btn', els =>
          els.map(el => ({ tag: el.tagName, text: el.textContent.trim().substring(0, 50), id: el.id }))
          .filter(e => e.text).slice(0, 30)
        );
        if (btns.length) {
          console.log('  按钮：');
          btns.forEach(b => console.log(`    ${b.tag}#${b.id}: "${b.text}"`));
        }
      }
    } catch { console.log(`  ✗ ${p} 超时`); }
  }
}

const result = await main();
if (result.success) {
  await explore(result.page);
  await result.browser.close();
} else {
  process.exit(1);
}
