const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');

const source = fs.readFileSync('sidepanel/sidepanel.js', 'utf8');

function extractFunction(name) {
  const markers = [`async function ${name}(`, `function ${name}(`];
  const start = markers
    .map((marker) => source.indexOf(marker))
    .find((index) => index >= 0);
  if (start < 0) {
    throw new Error(`missing function ${name}`);
  }

  let parenDepth = 0;
  let signatureEnded = false;
  let braceStart = -1;
  for (let i = start; i < source.length; i += 1) {
    const ch = source[i];
    if (ch === '(') {
      parenDepth += 1;
    } else if (ch === ')') {
      parenDepth -= 1;
      if (parenDepth === 0) {
        signatureEnded = true;
      }
    } else if (ch === '{' && signatureEnded) {
      braceStart = i;
      break;
    }
  }

  let depth = 0;
  let end = braceStart;
  for (; end < source.length; end += 1) {
    const ch = source[end];
    if (ch === '{') depth += 1;
    if (ch === '}') {
      depth -= 1;
      if (depth === 0) {
        end += 1;
        break;
      }
    }
  }

  return source.slice(start, end);
}

test('new user guide prompt is only eligible before the one-time dismissal is set', () => {
  const bundle = [
    extractFunction('isPromptDismissed'),
    extractFunction('setPromptDismissed'),
    extractFunction('isNewUserGuidePromptDismissed'),
    extractFunction('setNewUserGuidePromptDismissed'),
    extractFunction('shouldPromptNewUserGuide'),
  ].join('\n');

  const api = new Function(`
const NEW_USER_GUIDE_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-new-user-guide-prompt-dismissed';
const storage = new Map();
const localStorage = {
  getItem(key) {
    return storage.has(key) ? storage.get(key) : null;
  },
  setItem(key, value) {
    storage.set(key, String(value));
  },
  removeItem(key) {
    storage.delete(key);
  },
};
const btnContributionMode = { disabled: false };
let latestState = { contributionMode: false };
${bundle}
return {
  shouldPromptNewUserGuide,
  setDismissed(value) {
    setNewUserGuidePromptDismissed(value);
  },
  setButtonDisabled(value) {
    btnContributionMode.disabled = Boolean(value);
  },
  setContributionMode(value) {
    latestState = { contributionMode: Boolean(value) };
  },
};
`)();

  assert.equal(api.shouldPromptNewUserGuide(), true);

  api.setDismissed(true);
  assert.equal(api.shouldPromptNewUserGuide(), false);

  api.setDismissed(false);
  api.setButtonDisabled(true);
  assert.equal(api.shouldPromptNewUserGuide(), false);

  api.setButtonDisabled(false);
  api.setContributionMode(true);
  assert.equal(api.shouldPromptNewUserGuide(), false);
});

test('new user guide prompt persists dismissal before awaiting the user choice and opens the contribution page on confirm', async () => {
  const bundle = [
    extractFunction('isPromptDismissed'),
    extractFunction('setPromptDismissed'),
    extractFunction('isNewUserGuidePromptDismissed'),
    extractFunction('setNewUserGuidePromptDismissed'),
    extractFunction('shouldPromptNewUserGuide'),
    extractFunction('getContributionPortalUrl'),
    extractFunction('openNewUserGuidePrompt'),
    extractFunction('maybeShowNewUserGuidePrompt'),
  ].join('\n');

  const api = new Function(`
const NEW_USER_GUIDE_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-new-user-guide-prompt-dismissed';
const storage = new Map();
const localStorage = {
  getItem(key) {
    return storage.has(key) ? storage.get(key) : null;
  },
  setItem(key, value) {
    storage.set(key, String(value));
  },
  removeItem(key) {
    storage.delete(key);
  },
};
const btnContributionMode = { disabled: false };
const latestState = { contributionMode: false };
const contributionContentService = { portalUrl: 'https://apikey.qzz.io' };
const openedUrls = [];
let modalOptions = null;
let nextChoice = 'confirm';
function openExternalUrl(url) {
  openedUrls.push(url);
}
function openActionModal(options) {
  modalOptions = options;
  return Promise.resolve(nextChoice);
}
${bundle}
return {
  maybeShowNewUserGuidePrompt,
  getDismissed() {
    return localStorage.getItem(NEW_USER_GUIDE_PROMPT_DISMISSED_STORAGE_KEY);
  },
  getOpenedUrls() {
    return openedUrls.slice();
  },
  getModalOptions() {
    return modalOptions;
  },
  setNextChoice(choice) {
    nextChoice = choice;
  },
};
`)();

  const confirmed = await api.maybeShowNewUserGuidePrompt();
  const modalOptions = api.getModalOptions();

  assert.equal(confirmed, true);
  assert.equal(api.getDismissed(), '1');
  assert.deepStrictEqual(api.getOpenedUrls(), ['https://apikey.qzz.io']);
  assert.equal(modalOptions.title, '新手引导');
  assert.equal(modalOptions.alert.text, '本提示仅出现一次。');
  assert.deepStrictEqual(
    modalOptions.actions.map((item) => ({ id: item.id, label: item.label })),
    [
      { id: null, label: '取消' },
      { id: 'confirm', label: '查看引导' },
    ]
  );

  api.setNextChoice(null);
  const skipped = await api.maybeShowNewUserGuidePrompt();
  assert.equal(skipped, false);
  assert.deepStrictEqual(api.getOpenedUrls(), ['https://apikey.qzz.io']);
});
