import {
  GroupInteractionDeclineError,
  withClarifyTimeout,
} from '../../../../src/modules/netaclaw/runtime/errors.js';

describe('GroupInteractionDeclineError', () => {
  it('carries decline message and isInteractionDecline flag', () => {
    const err = new GroupInteractionDeclineError('⚠️ blocked');
    expect(err).toBeInstanceOf(Error);
    expect(err.isInteractionDecline).toBe(true);
    expect(err.declineMessage).toBe('⚠️ blocked');
    expect(err.message).toBe('⚠️ blocked');
    expect(err.name).toBe('GroupInteractionDeclineError');
  });
});

describe('withClarifyTimeout', () => {
  it('resolves through when the promise resolves before the timeout', async () => {
    const result = await withClarifyTimeout(Promise.resolve('ok'), 100);
    expect(result).toBe('ok');
  });

  it('rejects with GroupInteractionDeclineError after timeoutMs', async () => {
    jest.useFakeTimers();
    const pending = new Promise<string>(() => {/* never resolves */});
    const racing = withClarifyTimeout(pending, 300_000);
    jest.advanceTimersByTime(300_000);
    await expect(racing).rejects.toMatchObject({
      isInteractionDecline: true,
      declineMessage: expect.stringContaining('5 分钟'),
    });
    jest.useRealTimers();
  });

  it('clears the timeout when the promise resolves first so no orphan timer fires', async () => {
    jest.useFakeTimers();
    const resolved = Promise.resolve('ok');
    await withClarifyTimeout(resolved, 300_000);
    jest.advanceTimersByTime(300_000);
    jest.useRealTimers();
  });
});
