const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const mail2925Utils = require('../mail2925-utils.js');

const source = fs.readFileSync('background/mail-2925-session.js', 'utf8');
const globalScope = {};
const api = new Function('self', `${source}; return self.MultiPageBackgroundMail2925Session;`)(globalScope);

test('ensureMail2925MailboxSession reuses current mailbox page without sending login when page stays on mailList', async () => {
  let currentState = {
    autoRunning: false,
    mail2925Accounts: mail2925Utils.normalizeMail2925Accounts([
      { id: 'acc-1', email: 'acc1@2925.com', password: 'p1', enabled: true, lastUsedAt: 10 },
    ]),
    currentMail2925AccountId: 'acc-1',
  };
  let sendCalls = 0;
  let readyCalls = 0;

  const manager = api.createMail2925SessionManager({
    addLog: async () => {},
    broadcastDataUpdate: () => {},
    chrome: {
      tabs: {
        get: async () => ({ id: 9, url: 'https://2925.com/#/mailList' }),
      },
      cookies: {
        getAll: async () => [],
        remove: async () => ({ ok: true }),
      },
      browsingData: {
        removeCookies: async () => {},
      },
    },
    ensureContentScriptReadyOnTab: async () => {
      readyCalls += 1;
    },
    findMail2925Account: mail2925Utils.findMail2925Account,
    getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus,
    getState: async () => currentState,
    isAutoRunLockedState: () => false,
    isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable,
    MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS,
    normalizeMail2925Account: mail2925Utils.normalizeMail2925Account,
    normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts,
    pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun,
    reuseOrCreateTab: async () => 9,
    sendToMailContentScriptResilient: async () => {
      sendCalls += 1;
      return { loggedIn: true };
    },
    setPersistentSettings: async (payload) => {
      currentState = { ...currentState, ...payload };
    },
    setState: async (updates) => {
      currentState = { ...currentState, ...updates };
    },
    throwIfStopped: () => {},
    upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList,
  });

  const result = await manager.ensureMail2925MailboxSession({
    accountId: 'acc-1',
    forceRelogin: false,
    allowLoginWhenOnLoginPage: true,
    actionLabel: '步骤 8：确认 2925 邮箱登录态',
  });

  assert.equal(sendCalls, 0);
  assert.equal(readyCalls, 1);
  assert.equal(result.result.usedExistingSession, true);
});

test('ensureMail2925MailboxSession does not require account-pool accounts when pool is off and mailbox page stays on mailList', async () => {
  let currentState = {
    autoRunning: false,
    mail2925UseAccountPool: false,
    mail2925Accounts: [],
    currentMail2925AccountId: null,
  };
  let sendCalls = 0;

  const manager = api.createMail2925SessionManager({
    addLog: async () => {},
    broadcastDataUpdate: () => {},
    chrome: {
      tabs: {
        get: async () => ({ id: 9, url: 'https://2925.com/#/mailList' }),
      },
      cookies: {
        getAll: async () => [],
        remove: async () => ({ ok: true }),
      },
      browsingData: {
        removeCookies: async () => {},
      },
    },
    ensureContentScriptReadyOnTab: async () => {},
    findMail2925Account: mail2925Utils.findMail2925Account,
    getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus,
    getState: async () => currentState,
    isAutoRunLockedState: () => false,
    isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable,
    MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS,
    normalizeMail2925Account: mail2925Utils.normalizeMail2925Account,
    normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts,
    pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun,
    reuseOrCreateTab: async () => 9,
    sendToMailContentScriptResilient: async () => {
      sendCalls += 1;
      return { loggedIn: true };
    },
    setPersistentSettings: async (payload) => {
      currentState = { ...currentState, ...payload };
    },
    setState: async (updates) => {
      currentState = { ...currentState, ...updates };
    },
    throwIfStopped: () => {},
    upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList,
  });

  const result = await manager.ensureMail2925MailboxSession({
    accountId: null,
    forceRelogin: false,
    allowLoginWhenOnLoginPage: false,
    actionLabel: '步骤 4：确认 2925 邮箱登录态',
  });

  assert.equal(sendCalls, 0);
  assert.equal(result.result.usedExistingSession, true);
  assert.equal(result.account, null);
});

test('ensureMail2925MailboxSession stops immediately when login page is detected and account pool is off', async () => {
  let currentState = {
    autoRunning: true,
    autoRunPhase: 'running',
    mail2925Accounts: mail2925Utils.normalizeMail2925Accounts([
      { id: 'acc-1', email: 'acc1@2925.com', password: 'p1', enabled: true, lastUsedAt: 10 },
    ]),
    currentMail2925AccountId: 'acc-1',
  };
  const stopCalls = [];
  let sendCalls = 0;

  const manager = api.createMail2925SessionManager({
    addLog: async () => {},
    broadcastDataUpdate: () => {},
    chrome: {
      tabs: {
        get: async () => ({ id: 9, url: 'https://2925.com/login/' }),
      },
      cookies: {
        getAll: async () => [],
        remove: async () => ({ ok: true }),
      },
      browsingData: {
        removeCookies: async () => {},
      },
    },
    ensureContentScriptReadyOnTab: async () => {},
    findMail2925Account: mail2925Utils.findMail2925Account,
    getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus,
    getState: async () => currentState,
    isAutoRunLockedState: (state) => Boolean(state?.autoRunning) && state?.autoRunPhase === 'running',
    isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable,
    MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS,
    normalizeMail2925Account: mail2925Utils.normalizeMail2925Account,
    normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts,
    pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun,
    requestStop: async (options = {}) => {
      stopCalls.push(options);
    },
    reuseOrCreateTab: async () => 9,
    sendToMailContentScriptResilient: async () => {
      sendCalls += 1;
      return { loggedIn: true };
    },
    setPersistentSettings: async (payload) => {
      currentState = { ...currentState, ...payload };
    },
    setState: async (updates) => {
      currentState = { ...currentState, ...updates };
    },
    throwIfStopped: () => {},
    upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList,
  });

  await assert.rejects(
    () => manager.ensureMail2925MailboxSession({
      accountId: 'acc-1',
      forceRelogin: false,
      allowLoginWhenOnLoginPage: false,
      actionLabel: '步骤 4：确认 2925 邮箱登录态',
    }),
    /流程已被用户停止。/
  );

  assert.equal(sendCalls, 0);
  assert.equal(stopCalls.length, 1);
});

test('ensureMail2925MailboxSession logs in when login page is detected and account pool is on', async () => {
  let currentState = {
    autoRunning: false,
    mail2925Accounts: mail2925Utils.normalizeMail2925Accounts([
      { id: 'acc-1', email: 'acc1@2925.com', password: 'p1', enabled: true, lastUsedAt: 10 },
    ]),
    currentMail2925AccountId: 'acc-1',
  };
  let sendCalls = 0;
  let readyCalls = 0;

  const manager = api.createMail2925SessionManager({
    addLog: async () => {},
    broadcastDataUpdate: () => {},
    chrome: {
      tabs: {
        get: async () => ({ id: 9, url: 'https://2925.com/login/' }),
      },
      cookies: {
        getAll: async () => [],
        remove: async () => ({ ok: true }),
      },
      browsingData: {
        removeCookies: async () => {},
      },
    },
    ensureContentScriptReadyOnTab: async () => {
      readyCalls += 1;
    },
    findMail2925Account: mail2925Utils.findMail2925Account,
    getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus,
    getState: async () => currentState,
    isAutoRunLockedState: () => false,
    isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable,
    MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS,
    normalizeMail2925Account: mail2925Utils.normalizeMail2925Account,
    normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts,
    pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun,
    reuseOrCreateTab: async () => 9,
    sendToMailContentScriptResilient: async () => {
      sendCalls += 1;
      return { loggedIn: true, currentView: 'mailbox' };
    },
    setPersistentSettings: async (payload) => {
      currentState = { ...currentState, ...payload };
    },
    setState: async (updates) => {
      currentState = { ...currentState, ...updates };
    },
    throwIfStopped: () => {},
    upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList,
  });

  const result = await manager.ensureMail2925MailboxSession({
    accountId: 'acc-1',
    forceRelogin: false,
    allowLoginWhenOnLoginPage: true,
    actionLabel: '步骤 4：确认 2925 邮箱登录态',
  });

  assert.equal(sendCalls, 1);
  assert.equal(readyCalls, 1);
  assert.equal(result.result.loggedIn, true);
});

test('ensureMail2925MailboxSession recovers after login-page navigation reload breaks the old content-script channel', async () => {
  let currentState = {
    autoRunning: false,
    mail2925Accounts: mail2925Utils.normalizeMail2925Accounts([
      { id: 'acc-1', email: 'acc1@2925.com', password: 'p1', enabled: true, lastUsedAt: 10 },
    ]),
    currentMail2925AccountId: 'acc-1',
  };
  let tabUrl = 'https://2925.com/login/';
  const events = {
    logs: [],
    readyCalls: 0,
    sendCalls: 0,
    waitCompleteCalls: 0,
  };

  const manager = api.createMail2925SessionManager({
    addLog: async (message, level = 'info') => {
      events.logs.push({ message, level });
    },
    broadcastDataUpdate: () => {},
    chrome: {
      tabs: {
        get: async () => ({ id: 9, url: tabUrl, status: tabUrl.includes('/#/mailList') ? 'complete' : 'loading' }),
      },
      cookies: {
        getAll: async () => [],
        remove: async () => ({ ok: true }),
      },
      browsingData: {
        removeCookies: async () => {},
      },
    },
    ensureContentScriptReadyOnTab: async () => {
      events.readyCalls += 1;
    },
    findMail2925Account: mail2925Utils.findMail2925Account,
    getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus,
    getState: async () => currentState,
    isAutoRunLockedState: () => false,
    isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable,
    MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS,
    normalizeMail2925Account: mail2925Utils.normalizeMail2925Account,
    normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts,
    pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun,
    reuseOrCreateTab: async () => 9,
    sendToContentScriptResilient: async () => {
      events.sendCalls += 1;
      if (events.sendCalls === 1) {
        throw new Error('Could not establish connection. Receiving end does not exist.');
      }
      return { loggedIn: true, currentView: 'mailbox', mailboxEmail: 'acc1@2925.com' };
    },
    setPersistentSettings: async (payload) => {
      currentState = { ...currentState, ...payload };
    },
    setState: async (updates) => {
      currentState = { ...currentState, ...updates };
    },
    throwIfStopped: () => {},
    upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList,
    waitForTabComplete: async () => {
      events.waitCompleteCalls += 1;
      tabUrl = 'https://2925.com/#/mailList';
      return { id: 9, url: tabUrl, status: 'complete' };
    },
  });

  const result = await manager.ensureMail2925MailboxSession({
    accountId: 'acc-1',
    forceRelogin: false,
    allowLoginWhenOnLoginPage: true,
    actionLabel: '步骤 4：确认 2925 邮箱登录态',
  });

  assert.equal(events.sendCalls, 2);
  assert.equal(events.readyCalls, 2);
  assert.equal(events.waitCompleteCalls, 1);
  assert.equal(result.result.loggedIn, true);
  const combinedLogs = events.logs.map(({ message }) => message).join('\n');
  assert.match(combinedLogs, /登录提交后页面发生跳转或重载/);
  assert.match(combinedLogs, /登录跳转恢复后当前标签地址：https:\/\/2925\.com\/#\/mailList/);
  assert.match(combinedLogs, /页面恢复完成，正在重新确认登录态/);
});

test('ensureMail2925MailboxSession relogs with selected account when mailbox page email mismatches and pool is on', async () => {
  let currentState = {
    autoRunning: false,
    mail2925UseAccountPool: true,
    mail2925Accounts: mail2925Utils.normalizeMail2925Accounts([
      { id: 'acc-1', email: 'target@2925.com', password: 'p1', enabled: true, lastUsedAt: 10 },
    ]),
    currentMail2925AccountId: 'acc-1',
  };
  const openedUrls = [];
  const sendPayloads = [];

  const manager = api.createMail2925SessionManager({
    addLog: async () => {},
    broadcastDataUpdate: () => {},
    chrome: {
      tabs: {
        get: async () => ({ id: 9, url: openedUrls.at(-1) || 'https://2925.com/#/mailList' }),
      },
      cookies: {
        getAll: async () => [],
        remove: async () => ({ ok: true }),
      },
      browsingData: {
        removeCookies: async () => {},
      },
    },
    ensureContentScriptReadyOnTab: async () => {},
    findMail2925Account: mail2925Utils.findMail2925Account,
    getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus,
    getState: async () => currentState,
    isAutoRunLockedState: () => false,
    isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable,
    MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS,
    normalizeMail2925Account: mail2925Utils.normalizeMail2925Account,
    normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts,
    pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun,
    reuseOrCreateTab: async (_source, url) => {
      openedUrls.push(url);
      return 9;
    },
    sendToMailContentScriptResilient: async (_mail, message) => {
      sendPayloads.push(message.payload);
      if (sendPayloads.length === 1) {
        return {
          loggedIn: true,
          currentView: 'mailbox',
          mailboxEmail: 'wrong@2925.com',
        };
      }
      return {
        loggedIn: true,
        currentView: 'mailbox',
        mailboxEmail: 'target@2925.com',
      };
    },
    setPersistentSettings: async (payload) => {
      currentState = { ...currentState, ...payload };
    },
    setState: async (updates) => {
      currentState = { ...currentState, ...updates };
    },
    sleepWithStop: async () => {},
    throwIfStopped: () => {},
    upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList,
    waitForTabUrlMatch: async () => ({ url: 'https://2925.com/login/' }),
  });

  const result = await manager.ensureMail2925MailboxSession({
    accountId: 'acc-1',
    forceRelogin: false,
    allowLoginWhenOnLoginPage: true,
    expectedMailboxEmail: 'target@2925.com',
    actionLabel: '步骤 4：确认 2925 邮箱登录态',
  });

  assert.equal(result.result.loggedIn, true);
  assert.deepStrictEqual(openedUrls, [
    'https://2925.com/#/mailList',
    'https://2925.com/login/',
  ]);
  assert.equal(sendPayloads.length, 2);
  assert.equal(sendPayloads[0].allowLoginWhenOnLoginPage, true);
  assert.equal(sendPayloads[1].forceLogin, true);
});

test('ensureMail2925MailboxSession stops when mailbox page email mismatches and pool is off', async () => {
  let currentState = {
    autoRunning: true,
    autoRunPhase: 'running',
    mail2925UseAccountPool: false,
    mail2925Accounts: [],
    currentMail2925AccountId: null,
  };
  const stopCalls = [];
  let sendCalls = 0;

  const manager = api.createMail2925SessionManager({
    addLog: async () => {},
    broadcastDataUpdate: () => {},
    chrome: {
      tabs: {
        get: async () => ({ id: 9, url: 'https://2925.com/#/mailList' }),
      },
      cookies: {
        getAll: async () => [],
        remove: async () => ({ ok: true }),
      },
      browsingData: {
        removeCookies: async () => {},
      },
    },
    ensureContentScriptReadyOnTab: async () => {},
    findMail2925Account: mail2925Utils.findMail2925Account,
    getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus,
    getState: async () => currentState,
    isAutoRunLockedState: (state) => Boolean(state?.autoRunning) && state?.autoRunPhase === 'running',
    isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable,
    MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS,
    normalizeMail2925Account: mail2925Utils.normalizeMail2925Account,
    normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts,
    pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun,
    requestStop: async (options = {}) => {
      stopCalls.push(options);
    },
    reuseOrCreateTab: async () => 9,
    sendToMailContentScriptResilient: async () => {
      sendCalls += 1;
      return {
        loggedIn: true,
        currentView: 'mailbox',
        mailboxEmail: 'wrong@2925.com',
      };
    },
    setPersistentSettings: async (payload) => {
      currentState = { ...currentState, ...payload };
    },
    setState: async (updates) => {
      currentState = { ...currentState, ...updates };
    },
    throwIfStopped: () => {},
    upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList,
  });

  await assert.rejects(
    () => manager.ensureMail2925MailboxSession({
      accountId: null,
      forceRelogin: false,
      allowLoginWhenOnLoginPage: false,
      expectedMailboxEmail: 'target@2925.com',
      actionLabel: '步骤 4：确认 2925 邮箱登录态',
    }),
    /流程已被用户停止。/
  );

  assert.equal(sendCalls, 1);
  assert.equal(stopCalls.length, 1);
  assert.match(stopCalls[0].logMessage, /与目标账号 target@2925\.com 不一致/);
});

test('ensureMail2925MailboxSession does not crash when mailbox page is reused but top email cannot be detected', async () => {
  let currentState = {
    autoRunning: false,
    mail2925UseAccountPool: false,
    mail2925Accounts: [],
    currentMail2925AccountId: null,
  };
  let sendCalls = 0;

  const manager = api.createMail2925SessionManager({
    addLog: async () => {},
    broadcastDataUpdate: () => {},
    chrome: {
      tabs: {
        get: async () => ({ id: 9, url: 'https://2925.com/#/mailList' }),
      },
      cookies: {
        getAll: async () => [],
        remove: async () => ({ ok: true }),
      },
      browsingData: {
        removeCookies: async () => {},
      },
    },
    ensureContentScriptReadyOnTab: async () => {},
    findMail2925Account: mail2925Utils.findMail2925Account,
    getMail2925AccountStatus: mail2925Utils.getMail2925AccountStatus,
    getState: async () => currentState,
    isAutoRunLockedState: () => false,
    isMail2925AccountAvailable: mail2925Utils.isMail2925AccountAvailable,
    MAIL2925_LIMIT_COOLDOWN_MS: mail2925Utils.MAIL2925_LIMIT_COOLDOWN_MS,
    normalizeMail2925Account: mail2925Utils.normalizeMail2925Account,
    normalizeMail2925Accounts: mail2925Utils.normalizeMail2925Accounts,
    pickMail2925AccountForRun: mail2925Utils.pickMail2925AccountForRun,
    reuseOrCreateTab: async () => 9,
    sendToMailContentScriptResilient: async () => {
      sendCalls += 1;
      return {
        loggedIn: true,
        currentView: 'mailbox',
        mailboxEmail: '',
      };
    },
    setPersistentSettings: async (payload) => {
      currentState = { ...currentState, ...payload };
    },
    setState: async (updates) => {
      currentState = { ...currentState, ...updates };
    },
    throwIfStopped: () => {},
    upsertMail2925AccountInList: mail2925Utils.upsertMail2925AccountInList,
  });

  const result = await manager.ensureMail2925MailboxSession({
    accountId: null,
    forceRelogin: false,
    allowLoginWhenOnLoginPage: false,
    expectedMailboxEmail: 'target@2925.com',
    actionLabel: '步骤 4：确认 2925 邮箱登录态',
  });

  assert.equal(sendCalls, 1);
  assert.equal(result.account, null);
  assert.equal(result.result.usedExistingSession, true);
});
