'use strict';

/* eslint-disable new-cap */
// BigInt() is a standard JS function but triggers new-cap rule

// ============================================
// Mock Connection Factory
// ============================================

const createMockConnection = (overrides = {}) => {
    const states = {
        NOT_AUTHENTICATED: 1,
        AUTHENTICATED: 2,
        SELECTED: 3,
        LOGOUT: 4
    };

    const defaultMailbox = {
        path: 'INBOX',
        flags: new Set(['\\Seen', '\\Answered', '\\Flagged', '\\Deleted', '\\Draft']),
        permanentFlags: new Set(['\\*']),
        exists: 100,
        recent: 5,
        uidNext: 1000,
        uidValidity: BigInt(12345),
        noModseq: false
    };

    return {
        states,
        state: overrides.state || states.SELECTED,
        id: 'test-connection-id',
        capabilities: new Map(overrides.capabilities || [['IMAP4rev1', true]]),
        enabled: new Set(overrides.enabled || []),
        authCapabilities: new Map(),
        mailbox: overrides.mailbox || { ...defaultMailbox },
        namespace: overrides.namespace || { delimiter: '/', prefix: '' },
        expectCapabilityUpdate: overrides.expectCapabilityUpdate || false,
        log: {
            warn: () => {},
            info: () => {},
            error: () => {},
            debug: () => {},
            trace: () => {}
        },
        close: overrides.close || (() => {}),
        emit: overrides.emit || (() => {}),
        currentSelectCommand: false,
        messageFlagsAdd: overrides.messageFlagsAdd || (async () => {}),
        run: overrides.run || (async () => {}),
        exec:
            overrides.exec ||
            (async () => ({
                next: () => {},
                response: { attributes: [] }
            })),
        ...overrides
    };
};

// ============================================
// CAPABILITY Command Tests
// ============================================

const capabilityCommand = require('../lib/commands/capability');

module.exports['Commands: capability returns cached when available'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map([
            ['IMAP4rev1', true],
            ['IDLE', true]
        ]),
        expectCapabilityUpdate: false
    });

    const result = await capabilityCommand(connection);
    test.ok(result instanceof Map);
    test.equal(result.get('IDLE'), true);
    test.done();
};

module.exports['Commands: capability fetches when empty'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map(),
        exec: async () => ({ next: () => {} })
    });

    const result = await capabilityCommand(connection);
    test.ok(result instanceof Map);
    test.done();
};

module.exports['Commands: capability fetches when update expected'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        capabilities: new Map([['IMAP4rev1', true]]),
        expectCapabilityUpdate: true,
        exec: async () => {
            execCalled = true;
            return { next: () => {} };
        }
    });

    await capabilityCommand(connection);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: capability handles error'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map(),
        exec: async () => {
            throw new Error('Command failed');
        }
    });

    const result = await capabilityCommand(connection);
    test.equal(result, false);
    test.done();
};

// ============================================
// NOOP Command Tests
// ============================================

const noopCommand = require('../lib/commands/noop');

module.exports['Commands: noop success'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        exec: async cmd => {
            test.equal(cmd, 'NOOP');
            execCalled = true;
            return { next: () => {} };
        }
    });

    const result = await noopCommand(connection);
    test.equal(result, true);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: noop handles error'] = async test => {
    const connection = createMockConnection({
        exec: async () => {
            throw new Error('Command failed');
        }
    });

    const result = await noopCommand(connection);
    test.equal(result, false);
    test.done();
};

// ============================================
// LOGIN Command Tests
// ============================================

const loginCommand = require('../lib/commands/login');

module.exports['Commands: login success'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 1, // NOT_AUTHENTICATED
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    const result = await loginCommand(connection, 'testuser', 'testpass');
    test.equal(result, 'testuser');
    test.equal(execArgs.cmd, 'LOGIN');
    test.equal(execArgs.attrs[0].value, 'testuser');
    test.equal(execArgs.attrs[1].value, 'testpass');
    test.equal(execArgs.attrs[1].sensitive, true);
    test.done();
};

module.exports['Commands: login skips when already authenticated'] = async test => {
    const connection = createMockConnection({
        state: 2 // AUTHENTICATED
    });

    const result = await loginCommand(connection, 'testuser', 'testpass');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: login handles error'] = async test => {
    const connection = createMockConnection({
        state: 1,
        exec: async () => {
            const err = new Error('Auth failed');
            err.response = { attributes: [] };
            throw err;
        }
    });

    try {
        await loginCommand(connection, 'testuser', 'wrongpass');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.authenticationFailed, true);
    }
    test.done();
};

module.exports['Commands: login error includes serverResponseCode'] = async test => {
    const connection = createMockConnection({
        state: 1,
        exec: async () => {
            const err = new Error('Auth failed');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'AUTHENTICATIONFAILED' }]
                    },
                    { type: 'TEXT', value: 'Authentication failed' }
                ]
            };
            throw err;
        }
    });

    try {
        await loginCommand(connection, 'testuser', 'wrongpass');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.authenticationFailed, true);
        test.equal(err.serverResponseCode, 'AUTHENTICATIONFAILED');
    }
    test.done();
};

// ============================================
// LOGOUT Command Tests
// ============================================

const logoutCommand = require('../lib/commands/logout');

module.exports['Commands: logout success'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        exec: async cmd => {
            test.equal(cmd, 'LOGOUT');
            execCalled = true;
            return { next: () => {} };
        }
    });

    const result = await logoutCommand(connection);
    test.equal(result, true);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: logout handles error'] = async test => {
    const connection = createMockConnection({
        exec: async () => {
            throw new Error('Command failed');
        }
    });

    const result = await logoutCommand(connection);
    test.equal(result, false);
    test.done();
};

module.exports['Commands: logout returns early when already in LOGOUT state'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 4, // LOGOUT
        exec: async () => {
            execCalled = true;
            return { next: () => {} };
        }
    });

    const result = await logoutCommand(connection);
    test.equal(result, false);
    test.equal(execCalled, false);
    test.done();
};

module.exports['Commands: logout handles NOT_AUTHENTICATED state'] = async test => {
    let closeCalled = false;
    const connection = createMockConnection({
        state: 1, // NOT_AUTHENTICATED (mock states: 1=NOT_AUTH, 2=AUTH, 3=SELECTED, 4=LOGOUT)
        exec: async () => ({ next: () => {} }),
        close: () => {
            closeCalled = true;
        }
    });

    const result = await logoutCommand(connection);
    test.equal(result, false);
    test.equal(connection.state, connection.states.LOGOUT);
    test.equal(closeCalled, true);
    test.done();
};

module.exports['Commands: logout handles NoConnection error'] = async test => {
    const connection = createMockConnection({
        exec: async () => {
            const err = new Error('No connection');
            err.code = 'NoConnection';
            throw err;
        }
    });

    const result = await logoutCommand(connection);
    test.equal(result, true);
    test.done();
};

// ============================================
// CLOSE Command Tests
// ============================================

const closeCommand = require('../lib/commands/close');

module.exports['Commands: close success'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 3, // SELECTED
        exec: async cmd => {
            test.equal(cmd, 'CLOSE');
            execCalled = true;
            return { next: () => {} };
        }
    });

    const result = await closeCommand(connection);
    test.equal(result, true);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: close skips when not selected'] = async test => {
    const connection = createMockConnection({
        state: 2 // AUTHENTICATED, not SELECTED
    });

    const result = await closeCommand(connection);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: close handles error'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            throw new Error('Command failed');
        }
    });

    const result = await closeCommand(connection);
    test.equal(result, false);
    test.done();
};

module.exports['Commands: close emits mailboxClose event'] = async test => {
    let emittedMailbox = null;
    const testMailbox = { path: 'INBOX', uidValidity: 12345n };
    const connection = createMockConnection({
        state: 3,
        mailbox: testMailbox,
        currentSelectCommand: { command: 'SELECT', arguments: [{ value: 'INBOX' }] },
        exec: async () => ({ next: () => {} }),
        emit: (event, data) => {
            if (event === 'mailboxClose') {
                emittedMailbox = data;
            }
        }
    });

    const result = await closeCommand(connection);
    test.equal(result, true);
    test.ok(emittedMailbox);
    test.equal(emittedMailbox.path, 'INBOX');
    test.equal(connection.mailbox, false);
    test.equal(connection.currentSelectCommand, false);
    test.equal(connection.state, 2); // AUTHENTICATED
    test.done();
};

module.exports['Commands: close without mailbox does not emit event'] = async test => {
    let eventEmitted = false;
    const connection = createMockConnection({
        state: 3,
        mailbox: false, // No mailbox
        exec: async () => ({ next: () => {} }),
        emit: event => {
            if (event === 'mailboxClose') {
                eventEmitted = true;
            }
        }
    });

    const result = await closeCommand(connection);
    test.equal(result, true);
    test.equal(eventEmitted, false);
    test.done();
};

// ============================================
// SEARCH Command Tests
// ============================================

const searchCommand = require('../lib/commands/search');

module.exports['Commands: search with ALL'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            execArgs = { cmd, attrs };
            // Simulate SEARCH response
            if (opts && opts.untagged && opts.untagged.SEARCH) {
                await opts.untagged.SEARCH({
                    attributes: [{ value: '1' }, { value: '2' }, { value: '3' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await searchCommand(connection, true, {});
    test.deepEqual(result, [1, 2, 3]);
    test.equal(execArgs.cmd, 'SEARCH');
    test.done();
};

module.exports['Commands: search with UID option'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            execCmd = cmd;
            if (opts && opts.untagged && opts.untagged.SEARCH) {
                await opts.untagged.SEARCH({ attributes: [{ value: '100' }] });
            }
            return { next: () => {} };
        }
    });

    const result = await searchCommand(connection, { all: true }, { uid: true });
    test.deepEqual(result, [100]);
    test.equal(execCmd, 'UID SEARCH');
    test.done();
};

module.exports['Commands: search with query object'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            // Check that search compiler was used
            test.ok(attrs.some(a => a.value === 'FROM'));
            if (opts && opts.untagged && opts.untagged.SEARCH) {
                await opts.untagged.SEARCH({ attributes: [] });
            }
            return { next: () => {} };
        }
    });

    const result = await searchCommand(connection, { from: 'test@example.com' }, {});
    test.ok(Array.isArray(result));
    test.done();
};

module.exports['Commands: search skips when not selected'] = async test => {
    const connection = createMockConnection({
        state: 2 // AUTHENTICATED
    });

    const result = await searchCommand(connection, { all: true }, {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: search handles error'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            const err = new Error('Search failed');
            err.response = { attributes: [] };
            throw err;
        }
    });

    const result = await searchCommand(connection, { all: true }, {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: search returns false for invalid query'] = async test => {
    const connection = createMockConnection({ state: 3 });

    const result = await searchCommand(connection, 'invalid-query', {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: search error with serverResponseCode'] = async test => {
    let capturedErr = null;
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            const err = new Error('Search failed');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'CANNOT' }]
                    },
                    { type: 'TEXT', value: 'Search not allowed' }
                ]
            };
            throw err;
        },
        log: {
            warn: data => {
                capturedErr = data.err;
            },
            info: () => {},
            debug: () => {},
            trace: () => {},
            error: () => {}
        }
    });

    const result = await searchCommand(connection, { all: true }, {});
    test.equal(result, false);
    test.ok(capturedErr);
    test.equal(capturedErr.serverResponseCode, 'CANNOT');
    test.done();
};

// ============================================
// STORE Command Tests
// ============================================

const storeCommand = require('../lib/commands/store');

module.exports['Commands: store add flags'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    const result = await storeCommand(connection, '1:10', ['\\Seen'], { operation: 'add' });
    test.equal(result, true);
    test.equal(execArgs.cmd, 'STORE');
    test.ok(execArgs.attrs[1].value.startsWith('+'));
    test.done();
};

module.exports['Commands: store remove flags'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    const result = await storeCommand(connection, '1:10', ['\\Seen'], { operation: 'remove' });
    test.equal(result, true);
    test.ok(execArgs.attrs[1].value.startsWith('-'));
    test.done();
};

module.exports['Commands: store remove keeps a flag not in permanentFlags'] = async test => {
    // Mailbox permits only \Seen (no \*), so \Custom is not a permanent flag. Removal must still be
    // sent: a flag does not need to be permitted to be removed. Regression guard — the check used
    // to test the rewritten wire-form operation instead of options.operation and dropped the flag.
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        mailbox: { permanentFlags: new Set(['\\Seen']) },
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    const result = await storeCommand(connection, '1:10', ['\\Custom'], { operation: 'remove' });
    test.equal(result, true);
    test.ok(execArgs, 'a STORE command should be issued');
    test.equal(execArgs.attrs[1].value, '-FLAGS');
    test.deepEqual(
        execArgs.attrs[2].map(flag => flag.value),
        ['\\Custom'],
        'the removed flag must be present in the command'
    );
    test.done();
};

module.exports['Commands: store add drops a flag not in permanentFlags'] = async test => {
    // Control for the regression above: the permanentFlags guard must still apply to non-remove
    // operations. Adding a flag the mailbox does not permit yields no command and a false result.
    let execCalled = false;
    const connection = createMockConnection({
        state: 3,
        mailbox: { permanentFlags: new Set(['\\Seen']) },
        exec: async () => {
            execCalled = true;
            return { next: () => {} };
        }
    });

    const result = await storeCommand(connection, '1:10', ['\\Custom'], { operation: 'add' });
    test.equal(result, false, 'adding a non-permitted flag should fail');
    test.equal(execCalled, false, 'no STORE command should be issued');
    test.done();
};

module.exports['Commands: store set flags'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    const result = await storeCommand(connection, '1:10', ['\\Seen'], { operation: 'set' });
    test.equal(result, true);
    test.ok(!execArgs.attrs[1].value.startsWith('+'));
    test.ok(!execArgs.attrs[1].value.startsWith('-'));
    test.done();
};

module.exports['Commands: store with UID'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3,
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    await storeCommand(connection, '100', ['\\Flagged'], { uid: true });
    test.equal(execCmd, 'UID STORE');
    test.done();
};

module.exports['Commands: store with silent'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    await storeCommand(connection, '1', ['\\Seen'], { silent: true });
    test.ok(execArgs.attrs[1].value.includes('.SILENT'));
    test.done();
};

module.exports['Commands: store with Gmail labels'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['X-GM-EXT-1', true]]),
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    await storeCommand(connection, '1', ['Important'], { useLabels: true });
    test.ok(execArgs.attrs[1].value.includes('X-GM-LABELS'));
    test.done();
};

module.exports['Commands: store skips when labels not supported'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map() // No X-GM-EXT-1
    });

    const result = await storeCommand(connection, '1', ['Label'], { useLabels: true });
    test.equal(result, false);
    test.done();
};

module.exports['Commands: store skips when not selected'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await storeCommand(connection, '1:10', ['\\Seen'], {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: store skips when no range'] = async test => {
    const connection = createMockConnection({ state: 3 });

    const result = await storeCommand(connection, null, ['\\Seen'], {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: store with CONDSTORE'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        enabled: new Set(['CONDSTORE']),
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    await storeCommand(connection, '1', ['\\Seen'], { unchangedSince: 12345 });
    test.ok(execArgs.attrs.some(a => Array.isArray(a) && a.some(x => x.value === 'UNCHANGEDSINCE')));
    test.done();
};

module.exports['Commands: store handles error'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            const err = new Error('Store failed');
            err.response = { attributes: [] };
            throw err;
        }
    });

    const result = await storeCommand(connection, '1', ['\\Seen'], {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: store error with serverResponseCode'] = async test => {
    let capturedErr = null;
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            const err = new Error('Store failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'CANNOT' }]
                    },
                    { type: 'TEXT', value: 'Cannot modify flags' }
                ]
            };
            throw err;
        },
        log: {
            warn: data => {
                capturedErr = data.err;
            }
        }
    });

    const result = await storeCommand(connection, '1', ['\\Seen'], {});
    test.equal(result, false);
    test.ok(capturedErr);
    test.equal(capturedErr.serverResponseCode, 'CANNOT');
    test.done();
};

module.exports['Commands: store filters flags that cannot be used'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 3,
        mailbox: {
            permanentFlags: new Set(['\\Seen']) // Only \\Seen is allowed
        },
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return { next: () => {} };
        }
    });

    // Try to add \\Deleted which is not in permanentFlags
    const result = await storeCommand(connection, '1', ['\\Seen', '\\Deleted'], { operation: 'add' });
    test.equal(result, true);
    test.ok(execAttrs);
    // Flags list should only contain \\Seen
    const flagsList = execAttrs[2];
    test.equal(flagsList.length, 1);
    test.equal(flagsList[0].value, '\\Seen');
    test.done();
};

module.exports['Commands: store remove operation uses minus prefix'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return { next: () => {} };
        }
    });

    const result = await storeCommand(connection, '1', ['\\Seen', '\\Deleted'], { operation: 'remove' });
    test.equal(result, true);
    test.ok(execAttrs);
    // Remove operation should use -FLAGS prefix
    test.equal(execAttrs[1].value, '-FLAGS');
    const flagsList = execAttrs[2];
    test.equal(flagsList.length, 2);
    test.done();
};

module.exports['Commands: store returns false when no valid flags for add'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: {
            permanentFlags: new Set() // No flags allowed
        }
    });

    // All flags get filtered out
    const result = await storeCommand(connection, '1', ['\\Seen', '\\Deleted'], { operation: 'add' });
    test.equal(result, false);
    test.done();
};

module.exports['Commands: store allows empty flags for set operation'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 3,
        mailbox: {
            permanentFlags: new Set() // No flags allowed, all get filtered
        },
        exec: async () => {
            execCalled = true;
            return { next: () => {} };
        }
    });

    // Set operation with empty flags should still proceed (to clear flags)
    const result = await storeCommand(connection, '1', ['\\Seen'], { operation: 'set' });
    test.equal(result, true);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: store returns false with empty flags for remove'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: {
            permanentFlags: new Set()
        }
    });

    // Remove with no valid flags should return false (nothing to remove)
    const result = await storeCommand(connection, '1', [], { operation: 'remove' });
    test.equal(result, false);
    test.done();
};

module.exports['Commands: store default operation is add'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return { next: () => {} };
        }
    });

    await storeCommand(connection, '1', ['\\Seen'], {}); // No operation specified
    test.ok(execAttrs);
    test.equal(execAttrs[1].value, '+FLAGS');
    test.done();
};

module.exports['Commands: store with labels uses X-GM-LABELS'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['X-GM-EXT-1', true]]),
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return { next: () => {} };
        }
    });

    await storeCommand(connection, '1', ['Important'], { useLabels: true, operation: 'add' });
    test.ok(execAttrs);
    test.equal(execAttrs[1].value, '+X-GM-LABELS');
    test.done();
};

module.exports['Commands: store silent does not apply to labels'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['X-GM-EXT-1', true]]),
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return { next: () => {} };
        }
    });

    // When using labels, silent flag should not add .SILENT suffix
    await storeCommand(connection, '1', ['Important'], { useLabels: true, silent: true, operation: 'set' });
    test.ok(execAttrs);
    test.equal(execAttrs[1].value, 'X-GM-LABELS'); // Not X-GM-LABELS.SILENT
    test.done();
};

// ============================================
// COPY Command Tests
// ============================================

const copyCommand = require('../lib/commands/copy');

module.exports['Commands: copy success'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    const result = await copyCommand(connection, '1:10', 'Archive', {});
    test.ok(result);
    test.equal(result.destination, 'Archive');
    test.equal(execArgs.cmd, 'COPY');
    test.done();
};

module.exports['Commands: copy with UID'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3,
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    await copyCommand(connection, '100', 'Archive', { uid: true });
    test.equal(execCmd, 'UID COPY');
    test.done();
};

module.exports['Commands: copy with COPYUID response'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [{ value: 'COPYUID' }, { value: '12345' }, { value: '1:3' }, { value: '100:102' }]
                    }
                ]
            }
        })
    });

    const result = await copyCommand(connection, '1:3', 'Archive', {});
    test.ok(result.uidValidity);
    test.ok(result.uidMap instanceof Map);
    test.equal(result.uidMap.get(1), 100);
    test.equal(result.uidMap.get(2), 101);
    test.equal(result.uidMap.get(3), 102);
    test.done();
};

module.exports['Commands: copy skips when not selected'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await copyCommand(connection, '1:10', 'Archive', {});
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: copy skips when no range'] = async test => {
    const connection = createMockConnection({ state: 3 });

    const result = await copyCommand(connection, null, 'Archive', {});
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: copy skips when no destination'] = async test => {
    const connection = createMockConnection({ state: 3 });

    const result = await copyCommand(connection, '1:10', null, {});
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: copy handles error'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            const err = new Error('Copy failed');
            err.response = { attributes: [] };
            throw err;
        }
    });

    const result = await copyCommand(connection, '1:10', 'Archive', {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: copy error with serverResponseCode'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            const err = new Error('Copy failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'TRYCREATE' }]
                    },
                    { type: 'TEXT', value: 'Mailbox does not exist' }
                ]
            };
            throw err;
        }
    });

    const result = await copyCommand(connection, '1:10', 'NonExistent', {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: copy with partial COPYUID response'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX' },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [
                            { type: 'ATOM', value: 'COPYUID' },
                            { type: 'ATOM', value: '12345' }
                            // Missing source and destination UIDs
                        ]
                    }
                ]
            }
        })
    });

    const result = await copyCommand(connection, '1:10', 'Archive', {});
    test.ok(result);
    test.equal(result.path, 'INBOX');
    test.equal(result.destination, 'Archive');
    test.equal(result.uidValidity, 12345n);
    test.equal(result.uidMap, undefined);
    test.done();
};

module.exports['Commands: copy with invalid uidValidity'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX' },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [
                            { type: 'ATOM', value: 'COPYUID' },
                            { type: 'ATOM', value: 'invalid' } // Non-numeric uidValidity
                        ]
                    }
                ]
            }
        })
    });

    const result = await copyCommand(connection, '1:10', 'Archive', {});
    test.ok(result);
    test.equal(result.uidValidity, undefined);
    test.done();
};

module.exports['Commands: copy with mismatched UID counts'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX' },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [
                            { type: 'ATOM', value: 'COPYUID' },
                            { type: 'ATOM', value: '12345' },
                            { type: 'ATOM', value: '1:3' }, // 3 source UIDs
                            { type: 'ATOM', value: '100:101' } // 2 destination UIDs
                        ]
                    }
                ]
            }
        })
    });

    const result = await copyCommand(connection, '1:3', 'Archive', {});
    test.ok(result);
    test.equal(result.uidValidity, 12345n);
    test.equal(result.uidMap, undefined); // Not set due to mismatch
    test.done();
};

module.exports['Commands: copy with non-COPYUID response code'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX' },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [{ type: 'ATOM', value: 'APPENDUID' }] // Not COPYUID
                    }
                ]
            }
        })
    });

    const result = await copyCommand(connection, '1:10', 'Archive', {});
    test.ok(result);
    test.equal(result.path, 'INBOX');
    test.equal(result.destination, 'Archive');
    test.equal(result.uidValidity, undefined);
    test.equal(result.uidMap, undefined);
    test.done();
};

// ============================================
// MOVE Command Tests
// ============================================

const moveCommand = require('../lib/commands/move');

module.exports['Commands: move with MOVE capability'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    await moveCommand(connection, '1:10', 'Archive', {});
    test.equal(execCmd, 'MOVE');
    test.done();
};

module.exports['Commands: move with UID and MOVE capability'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    await moveCommand(connection, '100', 'Archive', { uid: true });
    test.equal(execCmd, 'UID MOVE');
    test.done();
};

module.exports['Commands: move skips when not selected'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await moveCommand(connection, '1:10', 'Archive', {});
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: move skips when no range'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]])
    });

    const result = await moveCommand(connection, null, 'Archive', {});
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: move skips when no destination'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]])
    });

    const result = await moveCommand(connection, '1:10', null, {});
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: move fallback without MOVE capability'] = async test => {
    let copyCalled = false;
    let deleteCalled = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(), // No MOVE capability
        messageCopy: async (range, dest) => {
            copyCalled = true;
            test.equal(range, '1:10');
            test.equal(dest, 'Archive');
            return { path: 'INBOX', destination: 'Archive' };
        },
        messageDelete: async (range, opts) => {
            deleteCalled = true;
            test.equal(range, '1:10');
            test.equal(opts.silent, true);
            return true;
        }
    });

    const result = await moveCommand(connection, '1:10', 'Archive', {});
    test.ok(copyCalled);
    test.ok(deleteCalled);
    test.equal(result.destination, 'Archive');
    test.done();
};

module.exports['Commands: move fallback passes options'] = async test => {
    let copyOpts = null;
    let deleteOpts = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(), // No MOVE capability
        messageCopy: async (range, dest, opts) => {
            copyOpts = opts;
            return { path: 'INBOX', destination: dest };
        },
        messageDelete: async (range, opts) => {
            deleteOpts = opts;
            return true;
        }
    });

    await moveCommand(connection, '1:10', 'Archive', { uid: true });
    test.equal(copyOpts.uid, true);
    test.equal(deleteOpts.uid, true);
    test.equal(deleteOpts.silent, true);
    test.done();
};

module.exports['Commands: move with COPYUID response'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [{ value: 'COPYUID' }, { value: '12345' }, { value: '1:3' }, { value: '100:102' }]
                    }
                ]
            }
        })
    });

    const result = await moveCommand(connection, '1:3', 'Archive', {});
    test.ok(result.uidValidity);
    test.equal(result.uidValidity, BigInt(12345));
    test.ok(result.uidMap instanceof Map);
    test.equal(result.uidMap.get(1), 100);
    test.equal(result.uidMap.get(2), 101);
    test.equal(result.uidMap.get(3), 102);
    test.done();
};

module.exports['Commands: move handles COPYUID in untagged response'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async (cmd, attrs, opts) => {
            // Simulate untagged OK with COPYUID
            if (opts && opts.untagged && opts.untagged.OK) {
                await opts.untagged.OK({
                    attributes: [
                        {
                            section: [{ value: 'COPYUID' }, { value: '99999' }, { value: '5:7' }, { value: '200:202' }]
                        }
                    ]
                });
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    const result = await moveCommand(connection, '5:7', 'Archive', {});
    test.ok(result.uidMap instanceof Map);
    test.equal(result.uidMap.get(5), 200);
    test.equal(result.uidMap.get(6), 201);
    test.equal(result.uidMap.get(7), 202);
    test.done();
};

module.exports['Commands: move returns correct map structure'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async () => ({
            next: () => {},
            response: { attributes: [] }
        })
    });

    const result = await moveCommand(connection, '1:10', 'Archive', {});
    test.equal(result.path, 'INBOX');
    test.equal(result.destination, 'Archive');
    test.done();
};

module.exports['Commands: move handles error'] = async test => {
    let warnLogged = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async () => {
            const err = new Error('Move failed');
            err.response = { attributes: [] };
            throw err;
        },
        log: {
            warn: () => {
                warnLogged = true;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await moveCommand(connection, '1:10', 'Archive', {});
    test.equal(result, false);
    test.ok(warnLogged);
    test.done();
};

module.exports['Commands: move handles error with status code'] = async test => {
    let capturedErr = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async () => {
            const err = new Error('Move failed');
            // Provide response with TRYCREATE status code
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'ATOM',
                        value: '',
                        section: [{ type: 'ATOM', value: 'TRYCREATE' }]
                    },
                    { type: 'TEXT', value: 'Mailbox does not exist' }
                ]
            };
            throw err;
        },
        log: {
            warn: msg => {
                capturedErr = msg;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await moveCommand(connection, '1:10', 'NonExistent', {});
    test.equal(result, false);
    test.ok(capturedErr);
    test.done();
};

module.exports['Commands: move normalizes destination path'] = async test => {
    let capturedAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        namespace: { delimiter: '/', prefix: 'INBOX/' },
        exec: async (cmd, attrs) => {
            capturedAttrs = attrs;
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    await moveCommand(connection, '1:10', 'Archive', {});
    // The destination should be normalized
    test.ok(capturedAttrs);
    test.done();
};

module.exports['Commands: move handles COPYUID with invalid uidValidity'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [
                            { type: 'ATOM', value: 'COPYUID' },
                            { value: 'invalid' }, // Invalid uidValidity (NaN)
                            { value: '1:5' },
                            { value: '100:104' }
                        ]
                    }
                ]
            }
        })
    });

    const result = await moveCommand(connection, '1:5', 'Archive', {});
    test.ok(result);
    test.equal(result.uidValidity, undefined);
    test.done();
};

module.exports['Commands: move handles COPYUID with mismatched UID counts'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [
                            { type: 'ATOM', value: 'COPYUID' },
                            { value: '12345' },
                            { value: '1:5' }, // 5 source UIDs
                            { value: '100:102' } // Only 3 destination UIDs - mismatch
                        ]
                    }
                ]
            }
        })
    });

    const result = await moveCommand(connection, '1:5', 'Archive', {});
    test.ok(result);
    test.equal(result.uidValidity, BigInt(12345));
    test.equal(result.uidMap, undefined); // Not set due to mismatch
    test.done();
};

module.exports['Commands: move handles COPYUID with missing source/destination UIDs'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['MOVE', true]]),
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [
                            { type: 'ATOM', value: 'COPYUID' },
                            { value: '12345' },
                            { value: null }, // Missing source UIDs
                            { value: '100:104' }
                        ]
                    }
                ]
            }
        })
    });

    const result = await moveCommand(connection, '1:5', 'Archive', {});
    test.ok(result);
    test.equal(result.uidMap, undefined);
    test.done();
};

// ============================================
// EXPUNGE Command Tests
// ============================================

const expungeCommand = require('../lib/commands/expunge');

module.exports['Commands: expunge success'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 3,
        exec: async cmd => {
            test.equal(cmd, 'EXPUNGE');
            execCalled = true;
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, true);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: expunge with UID range'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['UIDPLUS', true]]),
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    await expungeCommand(connection, '1:100', { uid: true });
    test.equal(execCmd, 'UID EXPUNGE');
    test.done();
};

module.exports['Commands: expunge skips when not selected'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: expunge skips when no range'] = async test => {
    const connection = createMockConnection({ state: 3 });

    const result = await expungeCommand(connection, null, {});
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: expunge handles error'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            const err = new Error('Expunge failed');
            err.response = { attributes: [] };
            throw err;
        }
    });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: expunge parses HIGHESTMODSEQ response'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: { highestModseq: 100n },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [
                            { type: 'ATOM', value: 'HIGHESTMODSEQ' },
                            { type: 'ATOM', value: '9122' }
                        ]
                    }
                ]
            }
        })
    });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, true);
    test.equal(connection.mailbox.highestModseq, 9122n);
    test.done();
};

module.exports['Commands: expunge does not update lower HIGHESTMODSEQ'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: { highestModseq: 10000n },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [
                            { type: 'ATOM', value: 'HIGHESTMODSEQ' },
                            { type: 'ATOM', value: '5000' }
                        ]
                    }
                ]
            }
        })
    });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, true);
    test.equal(connection.mailbox.highestModseq, 10000n); // Should not be updated
    test.done();
};

module.exports['Commands: expunge handles invalid HIGHESTMODSEQ value'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: { highestModseq: 100n },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [
                            { type: 'ATOM', value: 'HIGHESTMODSEQ' },
                            { type: 'ATOM', value: 'invalid' }
                        ]
                    }
                ]
            }
        })
    });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, true);
    test.equal(connection.mailbox.highestModseq, 100n); // Should not be updated
    test.done();
};

module.exports['Commands: expunge updates HIGHESTMODSEQ when mailbox has none'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: {}, // No highestModseq
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [
                            { type: 'ATOM', value: 'HIGHESTMODSEQ' },
                            { type: 'ATOM', value: '500' }
                        ]
                    }
                ]
            }
        })
    });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, true);
    test.equal(connection.mailbox.highestModseq, 500n);
    test.done();
};

module.exports['Commands: expunge error with serverResponseCode'] = async test => {
    let capturedErr = null;
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            const err = new Error('Expunge failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'CANNOT' }]
                    },
                    { type: 'TEXT', value: 'Cannot expunge' }
                ]
            };
            throw err;
        },
        log: {
            warn: data => {
                capturedErr = data.err;
            }
        }
    });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, false);
    test.ok(capturedErr);
    test.equal(capturedErr.serverResponseCode, 'CANNOT');
    test.done();
};

module.exports['Commands: expunge without UID when UIDPLUS not available'] = async test => {
    let execCmd = null;
    let execAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(), // No UIDPLUS
        exec: async (cmd, attrs) => {
            execCmd = cmd;
            execAttrs = attrs;
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    await expungeCommand(connection, '1:100', { uid: true });
    test.equal(execCmd, 'EXPUNGE'); // Falls back to EXPUNGE
    test.equal(execAttrs, false); // No attributes for regular EXPUNGE
    test.done();
};

module.exports['Commands: expunge with UID EXPUNGE includes range'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['UIDPLUS', true]]),
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    await expungeCommand(connection, '1:50', { uid: true });
    test.ok(execAttrs);
    test.equal(execAttrs[0].type, 'SEQUENCE');
    test.equal(execAttrs[0].value, '1:50');
    test.done();
};

module.exports['Commands: expunge with non-HIGHESTMODSEQ response code'] = async test => {
    const connection = createMockConnection({
        state: 3,
        mailbox: { highestModseq: 100n },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [{ type: 'ATOM', value: 'OTHERCODE' }]
                    }
                ]
            }
        })
    });

    const result = await expungeCommand(connection, '1:*', {});
    test.equal(result, true);
    test.equal(connection.mailbox.highestModseq, 100n); // Should not be updated
    test.done();
};

// ============================================
// CREATE Command Tests
// ============================================

const createCommand = require('../lib/commands/create');

module.exports['Commands: create success'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {}, response: { attributes: [] } };
        }
    });

    const result = await createCommand(connection, 'NewFolder');
    test.ok(result);
    test.equal(result.created, true);
    test.equal(execArgs.cmd, 'CREATE');
    test.done();
};

module.exports['Commands: create skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 });

    const result = await createCommand(connection, 'NewFolder');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: create handles ALREADYEXISTS'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Mailbox already exists');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'ALREADYEXISTS' }]
                    },
                    { type: 'TEXT', value: 'Mailbox already exists' }
                ]
            };
            throw err;
        }
    });

    const result = await createCommand(connection, 'ExistingFolder');
    test.ok(result);
    test.equal(result.created, false);
    test.done();
};

module.exports['Commands: create throws on other errors'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Create failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [{ type: 'TEXT', value: 'Create failed' }]
            };
            throw err;
        }
    });

    try {
        await createCommand(connection, 'NewFolder');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.message.includes('Create failed'));
    }
    test.done();
};

// ============================================
// DELETE Command Tests
// ============================================

const deleteCommand = require('../lib/commands/delete');

module.exports['Commands: delete success'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 2,
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await deleteCommand(connection, 'OldFolder');
    test.ok(result);
    test.equal(result.path, 'OldFolder');
    test.equal(execCmd, 'DELETE');
    test.done();
};

module.exports['Commands: delete skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 });

    const result = await deleteCommand(connection, 'OldFolder');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: delete throws on error'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Delete failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [{ type: 'TEXT', value: 'Delete failed' }]
            };
            throw err;
        }
    });

    try {
        await deleteCommand(connection, 'OldFolder');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.message.includes('Delete failed'));
    }
    test.done();
};

module.exports['Commands: delete closes mailbox when deleting current mailbox'] = async test => {
    let closeCalled = false;
    let execCmd = null;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'FolderToDelete' },
        run: async cmd => {
            if (cmd === 'CLOSE') {
                closeCalled = true;
            }
        },
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await deleteCommand(connection, 'FolderToDelete');
    test.ok(closeCalled, 'CLOSE should be called');
    test.equal(execCmd, 'DELETE');
    test.ok(result);
    test.equal(result.path, 'FolderToDelete');
    test.done();
};

module.exports['Commands: delete does not close when deleting different mailbox'] = async test => {
    let closeCalled = false;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'INBOX' },
        run: async cmd => {
            if (cmd === 'CLOSE') {
                closeCalled = true;
            }
        },
        exec: async () => ({ next: () => {} })
    });

    const result = await deleteCommand(connection, 'OtherFolder');
    test.ok(!closeCalled, 'CLOSE should not be called');
    test.ok(result);
    test.equal(result.path, 'OtherFolder');
    test.done();
};

module.exports['Commands: delete works in SELECTED state'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'INBOX' },
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await deleteCommand(connection, 'SomeFolder');
    test.ok(result);
    test.equal(execCmd, 'DELETE');
    test.done();
};

module.exports['Commands: delete error with serverResponseCode'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Delete failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'NONEXISTENT' }]
                    },
                    { type: 'TEXT', value: 'Mailbox does not exist' }
                ]
            };
            throw err;
        }
    });

    try {
        await deleteCommand(connection, 'NonExistent');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.serverResponseCode, 'NONEXISTENT');
    }
    test.done();
};

module.exports['Commands: delete normalizes path'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, args) => {
            execArgs = args;
            return { next: () => {} };
        }
    });

    const result = await deleteCommand(connection, 'INBOX/Subfolder');
    test.ok(result);
    test.equal(result.path, 'INBOX/Subfolder');
    test.ok(execArgs);
    test.done();
};

// ============================================
// RENAME Command Tests
// ============================================

const renameCommand = require('../lib/commands/rename');

module.exports['Commands: rename success'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs) => {
            execArgs = { cmd, attrs };
            return { next: () => {} };
        }
    });

    const result = await renameCommand(connection, 'OldName', 'NewName');
    test.ok(result);
    test.equal(result.path, 'OldName');
    test.equal(result.newPath, 'NewName');
    test.equal(execArgs.cmd, 'RENAME');
    test.done();
};

module.exports['Commands: rename skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 });

    const result = await renameCommand(connection, 'OldName', 'NewName');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: rename throws on error'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Rename failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [{ type: 'TEXT', value: 'Rename failed' }]
            };
            throw err;
        }
    });

    try {
        await renameCommand(connection, 'OldName', 'NewName');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.message.includes('Rename failed'));
    }
    test.done();
};

module.exports['Commands: rename closes mailbox when renaming current mailbox'] = async test => {
    let closeCalled = false;
    let execCmd = null;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'OldFolder' },
        run: async cmd => {
            if (cmd === 'CLOSE') {
                closeCalled = true;
            }
        },
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await renameCommand(connection, 'OldFolder', 'NewFolder');
    test.ok(closeCalled, 'CLOSE should be called');
    test.equal(execCmd, 'RENAME');
    test.ok(result);
    test.equal(result.path, 'OldFolder');
    test.equal(result.newPath, 'NewFolder');
    test.done();
};

module.exports['Commands: rename does not close when renaming different mailbox'] = async test => {
    let closeCalled = false;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'INBOX' },
        run: async cmd => {
            if (cmd === 'CLOSE') {
                closeCalled = true;
            }
        },
        exec: async () => ({ next: () => {} })
    });

    const result = await renameCommand(connection, 'OtherFolder', 'NewName');
    test.ok(!closeCalled, 'CLOSE should not be called');
    test.ok(result);
    test.done();
};

module.exports['Commands: rename works in SELECTED state'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'INBOX' },
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await renameCommand(connection, 'SomeFolder', 'NewName');
    test.ok(result);
    test.equal(execCmd, 'RENAME');
    test.done();
};

module.exports['Commands: rename error with serverResponseCode'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Rename failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'NONEXISTENT' }]
                    },
                    { type: 'TEXT', value: 'Mailbox does not exist' }
                ]
            };
            throw err;
        }
    });

    try {
        await renameCommand(connection, 'NonExistent', 'NewName');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.serverResponseCode, 'NONEXISTENT');
    }
    test.done();
};

module.exports['Commands: rename normalizes paths'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, args) => {
            execArgs = args;
            return { next: () => {} };
        }
    });

    const result = await renameCommand(connection, 'INBOX/Old', 'INBOX/New');
    test.ok(result);
    test.equal(result.path, 'INBOX/Old');
    test.equal(result.newPath, 'INBOX/New');
    test.ok(execArgs);
    test.equal(execArgs.length, 2);
    test.done();
};

// ============================================
// SUBSCRIBE/UNSUBSCRIBE Command Tests
// ============================================

const subscribeCommand = require('../lib/commands/subscribe');
const unsubscribeCommand = require('../lib/commands/unsubscribe');

module.exports['Commands: subscribe success'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 2,
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await subscribeCommand(connection, 'Folder');
    test.equal(result, true);
    test.equal(execCmd, 'SUBSCRIBE');
    test.done();
};

module.exports['Commands: subscribe skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 });

    const result = await subscribeCommand(connection, 'Folder');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: unsubscribe success'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 2,
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await unsubscribeCommand(connection, 'Folder');
    test.equal(result, true);
    test.equal(execCmd, 'UNSUBSCRIBE');
    test.done();
};

module.exports['Commands: unsubscribe skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 });

    const result = await unsubscribeCommand(connection, 'Folder');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: subscribe works in SELECTED state'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3, // SELECTED
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await subscribeCommand(connection, 'Folder');
    test.equal(result, true);
    test.equal(execCmd, 'SUBSCRIBE');
    test.done();
};

module.exports['Commands: subscribe returns false on error'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Subscribe failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [{ type: 'TEXT', value: 'Subscribe failed' }]
            };
            throw err;
        }
    });

    const result = await subscribeCommand(connection, 'Folder');
    test.equal(result, false);
    test.done();
};

module.exports['Commands: subscribe error with serverResponseCode'] = async test => {
    let capturedErr = null;
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Subscribe failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'NONEXISTENT' }]
                    },
                    { type: 'TEXT', value: 'Mailbox does not exist' }
                ]
            };
            throw err;
        },
        log: {
            warn: data => {
                capturedErr = data.err;
            }
        }
    });

    const result = await subscribeCommand(connection, 'NonExistent');
    test.equal(result, false);
    test.ok(capturedErr);
    test.equal(capturedErr.serverResponseCode, 'NONEXISTENT');
    test.done();
};

module.exports['Commands: subscribe normalizes path'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, args) => {
            execArgs = args;
            return { next: () => {} };
        }
    });

    const result = await subscribeCommand(connection, 'INBOX/Subfolder');
    test.equal(result, true);
    test.ok(execArgs);
    test.equal(execArgs.length, 1);
    test.done();
};

module.exports['Commands: unsubscribe works in SELECTED state'] = async test => {
    let execCmd = null;
    const connection = createMockConnection({
        state: 3, // SELECTED
        exec: async cmd => {
            execCmd = cmd;
            return { next: () => {} };
        }
    });

    const result = await unsubscribeCommand(connection, 'Folder');
    test.equal(result, true);
    test.equal(execCmd, 'UNSUBSCRIBE');
    test.done();
};

module.exports['Commands: unsubscribe returns false on error'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Unsubscribe failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [{ type: 'TEXT', value: 'Unsubscribe failed' }]
            };
            throw err;
        }
    });

    const result = await unsubscribeCommand(connection, 'Folder');
    test.equal(result, false);
    test.done();
};

module.exports['Commands: unsubscribe error with serverResponseCode'] = async test => {
    let capturedErr = null;
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Unsubscribe failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'NONEXISTENT' }]
                    },
                    { type: 'TEXT', value: 'Mailbox does not exist' }
                ]
            };
            throw err;
        },
        log: {
            warn: data => {
                capturedErr = data.err;
            }
        }
    });

    const result = await unsubscribeCommand(connection, 'NonExistent');
    test.equal(result, false);
    test.ok(capturedErr);
    test.equal(capturedErr.serverResponseCode, 'NONEXISTENT');
    test.done();
};

module.exports['Commands: unsubscribe normalizes path'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, args) => {
            execArgs = args;
            return { next: () => {} };
        }
    });

    const result = await unsubscribeCommand(connection, 'INBOX/Subfolder');
    test.equal(result, true);
    test.ok(execArgs);
    test.equal(execArgs.length, 1);
    test.done();
};

// ============================================
// ENABLE Command Tests
// ============================================

const enableCommand = require('../lib/commands/enable');

module.exports['Commands: enable success'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        exec: async () => ({ next: () => {} })
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    // Returns Set of enabled extensions
    test.ok(result instanceof Set);
    test.done();
};

module.exports['Commands: enable skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: enable skips when ENABLE not supported'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map() // No ENABLE capability
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: enable handles error'] = async test => {
    const connection = createMockConnection({
        state: 2,
        // Need to include CONDSTORE so the filter doesn't skip it
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        exec: async () => {
            throw new Error('Enable failed');
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.equal(result, false);
    test.done();
};

// ============================================
// COMPRESS Command Tests
// ============================================

const compressCommand = require('../lib/commands/compress');

module.exports['Commands: compress success'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        capabilities: new Map([['COMPRESS=DEFLATE', true]]),
        exec: async () => {
            execCalled = true;
            return { next: () => {} };
        }
    });

    const result = await compressCommand(connection);
    test.equal(result, true);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: compress skips when not supported'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map() // No COMPRESS=DEFLATE
    });

    const result = await compressCommand(connection);
    // Returns false when not supported (not undefined)
    test.equal(result, false);
    test.done();
};

module.exports['Commands: compress handles error'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map([['COMPRESS=DEFLATE', true]]),
        exec: async () => {
            throw new Error('Compress failed');
        }
    });

    const result = await compressCommand(connection);
    test.equal(result, false);
    test.done();
};

// ============================================
// STARTTLS Command Tests
// ============================================

const starttlsCommand = require('../lib/commands/starttls');

module.exports['Commands: starttls success'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        capabilities: new Map([['STARTTLS', true]]),
        exec: async () => {
            execCalled = true;
            return { next: () => {} };
        }
    });

    const result = await starttlsCommand(connection);
    test.equal(result, true);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: starttls skips when not supported'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map() // No STARTTLS
    });

    const result = await starttlsCommand(connection);
    // Returns false when not supported (not undefined)
    test.equal(result, false);
    test.done();
};

module.exports['Commands: starttls handles error'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map([['STARTTLS', true]]),
        exec: async () => {
            throw new Error('STARTTLS failed');
        }
    });

    const result = await starttlsCommand(connection);
    test.equal(result, false);
    test.done();
};

// ============================================
// FETCH Command Tests
// ============================================

const fetchCommand = require('../lib/commands/fetch');

module.exports['Commands: fetch basic query'] = async test => {
    let execCalled = false;
    let execCommand = '';
    const connection = createMockConnection({
        state: 3, // SELECTED
        exec: async (cmd, attrs, opts) => {
            execCalled = true;
            execCommand = cmd;
            // Simulate a FETCH response
            if (opts && opts.untagged && opts.untagged.FETCH) {
                await opts.untagged.FETCH({
                    command: '1',
                    attributes: [
                        { value: '1' },
                        [{ type: 'ATOM', value: 'UID' }, { type: 'ATOM', value: '100' }, { type: 'ATOM', value: 'FLAGS' }, [{ value: '\\Seen' }]]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await fetchCommand(connection, '1:*', { uid: true, flags: true });
    test.equal(execCalled, true);
    test.equal(execCommand, 'FETCH');
    test.ok(result);
    test.equal(result.count, 1);
    test.ok(Array.isArray(result.list));
    test.done();
};

module.exports['Commands: fetch with UID option'] = async test => {
    let execCommand = '';
    const connection = createMockConnection({
        state: 3,
        exec: async cmd => {
            execCommand = cmd;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1:*', { uid: true }, { uid: true });
    test.equal(execCommand, 'UID FETCH');
    test.done();
};

module.exports['Commands: fetch skips when not selected'] = async test => {
    const connection = createMockConnection({ state: 2 }); // AUTHENTICATED, not SELECTED

    const result = await fetchCommand(connection, '1:*', { uid: true });
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: fetch skips when no range'] = async test => {
    const connection = createMockConnection({ state: 3 });

    const result = await fetchCommand(connection, null, { uid: true });
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: fetch with envelope query'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { envelope: true });
    test.ok(queryAttrs);
    // Check that ENVELOPE is in the query
    const hasEnvelope = JSON.stringify(queryAttrs).includes('ENVELOPE');
    test.ok(hasEnvelope);
    test.done();
};

module.exports['Commands: fetch with bodyStructure query'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { bodyStructure: true });
    test.ok(queryAttrs);
    const hasBODYSTRUCTURE = JSON.stringify(queryAttrs).includes('BODYSTRUCTURE');
    test.ok(hasBODYSTRUCTURE);
    test.done();
};

module.exports['Commands: fetch with size query'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { size: true });
    test.ok(queryAttrs);
    const hasRFC822SIZE = JSON.stringify(queryAttrs).includes('RFC822.SIZE');
    test.ok(hasRFC822SIZE);
    test.done();
};

module.exports['Commands: fetch with source query'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { source: true });
    test.ok(queryAttrs);
    const hasBODYPEEK = JSON.stringify(queryAttrs).includes('BODY.PEEK');
    test.ok(hasBODYPEEK);
    test.done();
};

module.exports['Commands: fetch with source partial'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { source: { start: 0, maxLength: 1024 } });
    test.ok(queryAttrs);
    // Partial should be set
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('BODY.PEEK'));
    test.done();
};

module.exports['Commands: fetch with BINARY capability'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['BINARY', true]]),
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { source: true }, { binary: true });
    test.ok(queryAttrs);
    const hasBINARYPEEK = JSON.stringify(queryAttrs).includes('BINARY.PEEK');
    test.ok(hasBINARYPEEK);
    test.done();
};

module.exports['Commands: fetch with OBJECTID capability'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['OBJECTID', true]]),
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { flags: true });
    test.ok(queryAttrs);
    const hasEMAILID = JSON.stringify(queryAttrs).includes('EMAILID');
    test.ok(hasEMAILID);
    test.done();
};

module.exports['Commands: fetch with X-GM-EXT-1 capability'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['X-GM-EXT-1', true]]),
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { flags: true });
    test.ok(queryAttrs);
    const hasXGMMSGID = JSON.stringify(queryAttrs).includes('X-GM-MSGID');
    test.ok(hasXGMMSGID);
    test.done();
};

module.exports['Commands: fetch with threadId query'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['OBJECTID', true]]),
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { threadId: true });
    test.ok(queryAttrs);
    const hasTHREADID = JSON.stringify(queryAttrs).includes('THREADID');
    test.ok(hasTHREADID);
    test.done();
};

module.exports['Commands: fetch with threadId and X-GM-EXT-1 fallback'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['X-GM-EXT-1', true]]), // No OBJECTID, but has X-GM-EXT-1
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { threadId: true });
    test.ok(queryAttrs);
    const hasXGMTHRID = JSON.stringify(queryAttrs).includes('X-GM-THRID');
    test.ok(hasXGMTHRID, 'Should use X-GM-THRID as fallback for threadId');
    test.done();
};

module.exports['Commands: fetch with labels query'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['X-GM-EXT-1', true]]),
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { labels: true });
    test.ok(queryAttrs);
    const hasXGMLABELS = JSON.stringify(queryAttrs).includes('X-GM-LABELS');
    test.ok(hasXGMLABELS);
    test.done();
};

module.exports['Commands: fetch with CONDSTORE enabled'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        enabled: new Set(['CONDSTORE']),
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { flags: true });
    test.ok(queryAttrs);
    const hasMODSEQ = JSON.stringify(queryAttrs).includes('MODSEQ');
    test.ok(hasMODSEQ);
    test.done();
};

module.exports['Commands: fetch with headers array'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { headers: ['Subject', 'From', 'To'] });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('HEADER.FIELDS'));
    test.done();
};

module.exports['Commands: fetch with headers true'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { headers: true });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('HEADER'));
    test.done();
};

module.exports['Commands: fetch with bodyParts'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { bodyParts: ['1', '2'] });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('BODY.PEEK'));
    test.done();
};

module.exports['Commands: fetch with bodyParts object'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { bodyParts: [{ key: '1', start: 0, maxLength: 100 }] });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('BODY.PEEK'));
    test.done();
};

module.exports['Commands: fetch with bodyParts skips invalid'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    // Invalid entries: null, object without key, number
    await fetchCommand(connection, '1', { bodyParts: [null, { noKey: true }, 123, '1'] });
    test.ok(queryAttrs);
    // Should still work - just skips invalid entries
    test.done();
};

module.exports['Commands: fetch with changedSince'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        enabled: new Set(['CONDSTORE']),
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { flags: true }, { changedSince: '12345' });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('CHANGEDSINCE'));
    test.done();
};

module.exports['Commands: fetch with changedSince and QRESYNC'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        enabled: new Set(['CONDSTORE', 'QRESYNC']),
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { flags: true }, { changedSince: '12345', uid: true });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('VANISHED'));
    test.done();
};

module.exports['Commands: fetch with onUntaggedFetch callback'] = async test => {
    let callbackCalled = false;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.FETCH) {
                await opts.untagged.FETCH({
                    command: '1',
                    attributes: [
                        { value: '1' },
                        [
                            { type: 'ATOM', value: 'UID' },
                            { type: 'ATOM', value: '100' }
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    await fetchCommand(
        connection,
        '1',
        { uid: true },
        {
            onUntaggedFetch: (msg, done) => {
                callbackCalled = true;
                done();
            }
        }
    );
    test.equal(callbackCalled, true);
    test.done();
};

module.exports['Commands: fetch callback error propagates'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.FETCH) {
                await opts.untagged.FETCH({
                    command: '1',
                    attributes: [
                        { value: '1' },
                        [
                            { type: 'ATOM', value: 'UID' },
                            { type: 'ATOM', value: '100' }
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    try {
        await fetchCommand(
            connection,
            '1',
            { uid: true },
            {
                onUntaggedFetch: (msg, done) => {
                    done(new Error('Callback error'));
                }
            }
        );
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.message, 'Callback error');
    }
    test.done();
};

module.exports['Commands: fetch handles error'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            throw new Error('Fetch failed');
        }
    });

    try {
        await fetchCommand(connection, '1', { uid: true });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.message, 'Fetch failed');
    }
    test.done();
};

module.exports['Commands: fetch retries on throttle error'] = async test => {
    let attempts = 0;
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            attempts++;
            if (attempts < 3) {
                const err = new Error('Throttled');
                err.code = 'ETHROTTLE';
                err.throttleReset = 10; // 10ms for testing
                throw err;
            }
            return { next: () => {} };
        }
    });

    const result = await fetchCommand(connection, '1', { uid: true });
    test.ok(result);
    test.equal(attempts, 3);
    test.done();
};

module.exports['Commands: fetch with all/fast/full query'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    await fetchCommand(connection, '1', { all: true, fast: true, full: true, internalDate: true });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('ALL'));
    test.ok(queryStr.includes('FAST'));
    test.ok(queryStr.includes('FULL'));
    test.ok(queryStr.includes('INTERNALDATE'));
    test.done();
};

// ============================================
// LIST Command Tests
// ============================================

const listCommand = require('../lib/commands/list');

module.exports['Commands: list basic'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            execCalled = true;
            // Simulate LIST response
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    test.equal(execCalled, true);
    test.ok(Array.isArray(result));
    test.done();
};

module.exports['Commands: list with XLIST capability'] = async test => {
    let usedListCommand = '';
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['XLIST', true]]),
        exec: async (cmd, attrs, opts) => {
            // Capture the first LIST/XLIST command, not LSUB
            if ((cmd === 'LIST' || cmd === 'XLIST') && !usedListCommand) {
                usedListCommand = cmd;
            }
            if (opts && opts.untagged && opts.untagged[cmd]) {
                await opts.untagged[cmd]({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    await listCommand(connection, '', '*');
    test.equal(usedListCommand, 'XLIST');
    test.done();
};

module.exports['Commands: list prefers LIST over XLIST when SPECIAL-USE available'] = async test => {
    let usedListCommand = '';
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([
            ['XLIST', true],
            ['SPECIAL-USE', true]
        ]),
        exec: async (cmd, attrs, opts) => {
            // Capture the first LIST/XLIST command, not LSUB
            if ((cmd === 'LIST' || cmd === 'XLIST') && !usedListCommand) {
                usedListCommand = cmd;
            }
            if (opts && opts.untagged && opts.untagged[cmd]) {
                await opts.untagged[cmd]({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    await listCommand(connection, '', '*');
    test.equal(usedListCommand, 'LIST');
    test.done();
};

module.exports['Commands: list with statusQuery'] = async test => {
    let listAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([
            ['LIST-STATUS', true],
            ['SPECIAL-USE', true]
        ]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST') {
                listAttrs = attrs;
                if (opts && opts.untagged && opts.untagged.LIST) {
                    await opts.untagged.LIST({
                        attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                    });
                }
                if (opts && opts.untagged && opts.untagged.STATUS) {
                    await opts.untagged.STATUS({
                        attributes: [{ value: 'INBOX' }, [{ value: 'MESSAGES' }, { value: '10' }, { value: 'UNSEEN' }, { value: '5' }]]
                    });
                }
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*', {
        statusQuery: { messages: true, unseen: true }
    });
    test.ok(listAttrs);
    const attrsStr = JSON.stringify(listAttrs);
    test.ok(attrsStr.includes('RETURN'));
    test.ok(attrsStr.includes('STATUS'));
    test.ok(Array.isArray(result));
    test.done();
};

module.exports['Commands: list with CONDSTORE status query'] = async test => {
    let listAttrs = null;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([
            ['LIST-STATUS', true],
            ['CONDSTORE', true]
        ]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST') {
                listAttrs = attrs;
                if (opts && opts.untagged && opts.untagged.LIST) {
                    await opts.untagged.LIST({
                        attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                    });
                }
            }
            return { next: () => {} };
        }
    });

    await listCommand(connection, '', '*', {
        statusQuery: { highestModseq: true }
    });
    test.ok(listAttrs);
    const attrsStr = JSON.stringify(listAttrs);
    test.ok(attrsStr.includes('HIGHESTMODSEQ'));
    test.done();
};

module.exports['Commands: list with listOnly option'] = async test => {
    let lsubCalled = false;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LSUB') {
                lsubCalled = true;
            }
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*', { listOnly: true });
    test.equal(lsubCalled, false);
    test.ok(Array.isArray(result));
    test.done();
};

module.exports['Commands: list with specialUseHints'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'Sent Items' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*', {
        specialUseHints: { sent: 'Sent Items' }
    });
    test.ok(Array.isArray(result));
    // The Sent Items folder should have specialUse set
    const sentFolder = result.find(e => e.path === 'Sent Items');
    test.ok(sentFolder);
    test.equal(sentFolder.specialUse, '\\Sent');
    test.done();
};

module.exports['Commands: list handles INBOX specially'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if ((cmd === 'LIST' || cmd === 'LSUB') && opts && opts.untagged) {
                const handler = opts.untagged[cmd];
                if (handler) {
                    await handler({
                        attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                    });
                }
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    const inbox = result.find(e => e.path === 'INBOX');
    test.ok(inbox);
    test.equal(inbox.specialUse, '\\Inbox');
    // INBOX should always be subscribed
    test.equal(inbox.subscribed, true);
    test.done();
};

module.exports['Commands: list runs separate INBOX query when using namespace'] = async test => {
    let listCalls = 0;
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST') {
                listCalls++;
                if (opts && opts.untagged && opts.untagged.LIST) {
                    // First call is for the namespace, second for INBOX
                    if (listCalls === 1) {
                        await opts.untagged.LIST({
                            attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX/Subfolder' }]
                        });
                    } else {
                        await opts.untagged.LIST({
                            attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                        });
                    }
                }
            }
            return { next: () => {} };
        }
    });

    await listCommand(connection, 'INBOX/', '*');
    // Should have called LIST twice - once for namespace, once for INBOX
    test.equal(listCalls, 2);
    test.done();
};

module.exports['Commands: list handles LSUB merging'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'Folder1' }]
                });
            }
            if (cmd === 'LSUB' && opts && opts.untagged && opts.untagged.LSUB) {
                await opts.untagged.LSUB({
                    attributes: [[{ value: '\\Subscribed' }], { value: '/' }, { value: 'Folder1' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    const folder = result.find(e => e.path === 'Folder1');
    test.ok(folder);
    test.equal(folder.subscribed, true);
    test.equal(folder.listed, true);
    test.done();
};

module.exports['Commands: list handles error'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async () => {
            throw new Error('List failed');
        }
    });

    try {
        await listCommand(connection, '', '*');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.message, 'List failed');
    }
    test.done();
};

module.exports['Commands: list handles empty attributes'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                // Empty attributes - should be skipped
                await opts.untagged.LIST({ attributes: [] });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    test.ok(Array.isArray(result));
    test.equal(result.length, 0);
    test.done();
};

module.exports['Commands: list status fallback when LIST-STATUS not supported'] = async test => {
    let statusCalls = 0;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(), // No LIST-STATUS
        // eslint-disable-next-line no-unused-vars
        run: async (cmd, path, query) => {
            if (cmd === 'STATUS') {
                statusCalls++;
                return { messages: 10, unseen: 5, path };
            }
        },
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*', {
        statusQuery: { messages: true, unseen: true }
    });
    test.ok(Array.isArray(result));
    // STATUS should have been called for each folder
    test.equal(statusCalls, 1);
    test.done();
};

module.exports['Commands: list handles STATUS errors gracefully'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(),
        run: async cmd => {
            if (cmd === 'STATUS') {
                throw new Error('Status failed');
            }
        },
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*', {
        statusQuery: { messages: true }
    });
    const inbox = result.find(e => e.path === 'INBOX');
    test.ok(inbox);
    // Status should have error property
    test.ok(inbox.status);
    test.ok(inbox.status.error);
    test.done();
};

module.exports['Commands: list sorts by special use'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                // Add folders out of order
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\Trash' }], { value: '/' }, { value: 'Trash' }]
                });
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\Sent' }], { value: '/' }, { value: 'Sent' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    // INBOX should be first (has \\Inbox special use)
    test.equal(result[0].specialUse, '\\Inbox');
    test.done();
};

module.exports['Commands: list handles delimiter in path'] = async test => {
    const connection = createMockConnection({
        state: 3,
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [
                        [{ value: '\\HasNoChildren' }],
                        { value: '/' },
                        { value: '/Leading/Slash' } // Path starts with delimiter
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    const folder = result.find(e => e.name === 'Slash');
    test.ok(folder);
    // Leading delimiter should be removed
    test.equal(folder.path, 'Leading/Slash');
    test.done();
};

module.exports['Commands: list skips Noselect folders for status'] = async test => {
    let statusCalls = 0;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(),
        run: async cmd => {
            if (cmd === 'STATUS') {
                statusCalls++;
                return { messages: 10 };
            }
        },
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\Noselect' }], { value: '/' }, { value: 'Parent' }]
                });
            }
            return { next: () => {} };
        }
    });

    await listCommand(connection, '', '*', { statusQuery: { messages: true } });
    // STATUS should not be called for Noselect folders
    test.equal(statusCalls, 0);
    test.done();
};

module.exports['Commands: list XLIST removes Inbox flag from non-INBOX'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['XLIST', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'XLIST' && opts && opts.untagged && opts.untagged.XLIST) {
                // XLIST may have localised inbox name with \\Inbox flag
                await opts.untagged.XLIST({
                    attributes: [
                        [{ value: '\\Inbox' }, { value: '\\HasNoChildren' }],
                        { value: '/' },
                        { value: 'Posteingang' } // German for inbox
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    const folder = result.find(e => e.path === 'Posteingang');
    test.ok(folder);
    // \\Inbox flag should be removed from flags set
    test.equal(folder.flags.has('\\Inbox'), false);
    // But it should have \\Inbox special use
    test.equal(folder.specialUse, '\\Inbox');
    test.done();
};

module.exports['Commands: list LSUB path with leading delimiter'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'Folder1' }]
                });
            }
            if (cmd === 'LSUB' && opts && opts.untagged && opts.untagged.LSUB) {
                // LSUB returns path with leading delimiter
                await opts.untagged.LSUB({
                    attributes: [
                        [{ value: '\\Subscribed' }],
                        { value: '/' },
                        { value: '/Folder1' } // Leading delimiter
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    const folder = result.find(e => e.path === 'Folder1');
    test.ok(folder);
    test.equal(folder.subscribed, true);
    test.done();
};

module.exports['Commands: list sorts non-special-use after special-use'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                // Regular folder first
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'ZFolder' }]
                });
                // Then INBOX (special use)
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    // INBOX (special use) should come before ZFolder (no special use)
    const inboxIndex = result.findIndex(e => e.path === 'INBOX');
    const zFolderIndex = result.findIndex(e => e.path === 'ZFolder');
    test.ok(inboxIndex < zFolderIndex, 'Special use folders should sort before non-special-use');
    test.done();
};

module.exports['Commands: list sorts alphabetically when no special use'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                // Folders without special use in reverse alphabetical order
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'Zebra' }]
                });
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'Alpha' }]
                });
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'Middle' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    // Should be sorted alphabetically
    const alphaIndex = result.findIndex(e => e.path === 'Alpha');
    const middleIndex = result.findIndex(e => e.path === 'Middle');
    const zebraIndex = result.findIndex(e => e.path === 'Zebra');
    test.ok(alphaIndex < middleIndex, 'Alpha should come before Middle');
    test.ok(middleIndex < zebraIndex, 'Middle should come before Zebra');
    test.done();
};

module.exports['Commands: list sorts nested folders by parent path'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                // Nested folders
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasChildren' }], { value: '/' }, { value: 'B' }]
                });
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'B/Nested' }]
                });
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasChildren' }], { value: '/' }, { value: 'A' }]
                });
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'A/Nested' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    // A folders should come before B folders
    const aIndex = result.findIndex(e => e.path === 'A');
    const aNestedIndex = result.findIndex(e => e.path === 'A/Nested');
    const bIndex = result.findIndex(e => e.path === 'B');
    const bNestedIndex = result.findIndex(e => e.path === 'B/Nested');
    test.ok(aIndex < bIndex, 'A should come before B');
    test.ok(aNestedIndex < bIndex, 'A/Nested should come before B');
    test.ok(bIndex < bNestedIndex || aNestedIndex < bNestedIndex, 'Parent folders sort correctly');
    test.done();
};

module.exports['Commands: list handles LSUB with empty attributes'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'TestFolder' }]
                });
            }
            if (cmd === 'LSUB' && opts && opts.untagged && opts.untagged.LSUB) {
                // Empty attributes
                await opts.untagged.LSUB({
                    attributes: []
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    test.ok(result.length >= 1);
    test.done();
};

module.exports['Commands: list handles STATUS NaN values in LSUB response'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([
            ['SPECIAL-USE', true],
            ['LIST-STATUS', true]
        ]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged) {
                if (opts.untagged.LIST) {
                    await opts.untagged.LIST({
                        attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'TestFolder' }]
                    });
                }
                if (opts.untagged.STATUS) {
                    await opts.untagged.STATUS({
                        attributes: [
                            { value: 'TestFolder' },
                            [
                                { value: 'MESSAGES' },
                                { value: 'NaN' }, // Invalid number
                                { value: 'RECENT' },
                                { value: 'invalid' } // Invalid value
                            ]
                        ]
                    });
                }
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*', { statusQuery: { messages: true, recent: true } });
    const folder = result.find(e => e.path === 'TestFolder');
    test.ok(folder);
    // NaN values should be filtered out (value === false check)
    test.equal(folder.status.messages, undefined);
    test.equal(folder.status.recent, undefined);
    test.done();
};

module.exports['Commands: list STATUS parses UIDVALIDITY UNSEEN HIGHESTMODSEQ'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([
            ['LIST-STATUS', true],
            ['CONDSTORE', true]
        ]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST') {
                if (opts && opts.untagged && opts.untagged.LIST) {
                    await opts.untagged.LIST({
                        attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'TestFolder' }]
                    });
                }
                if (opts && opts.untagged && opts.untagged.STATUS) {
                    await opts.untagged.STATUS({
                        attributes: [
                            { value: 'TestFolder' },
                            [
                                { value: 'UIDVALIDITY' },
                                { value: '123456789' },
                                { value: 'UNSEEN' },
                                { value: '42' },
                                { value: 'HIGHESTMODSEQ' },
                                { value: '999999999' }
                            ]
                        ]
                    });
                }
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*', {
        statusQuery: { uidValidity: true, unseen: true, highestModseq: true }
    });
    const folder = result.find(e => e.path === 'TestFolder');
    test.ok(folder);
    test.ok(folder.status);
    test.equal(folder.status.uidValidity, BigInt(123456789));
    test.equal(folder.status.unseen, 42);
    test.equal(folder.status.highestModseq, BigInt(999999999));
    test.done();
};

module.exports['Commands: list LSUB folder not in LIST entries'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                // Only return INBOX in LIST
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            if (cmd === 'LSUB' && opts && opts.untagged && opts.untagged.LSUB) {
                // Return a folder in LSUB that wasn't in LIST (hits else branch)
                await opts.untagged.LSUB({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'SubscribedOnly' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    // The subscribed-only folder should not be in results (else branch ignores it)
    const subscribedOnly = result.find(e => e.path === 'SubscribedOnly');
    test.equal(subscribedOnly, undefined);
    // INBOX should still be there
    const inbox = result.find(e => e.path === 'INBOX');
    test.ok(inbox);
    test.done();
};

module.exports['Commands: list sort b has specialUse a does not'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                // First add a folder without special use
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'AAA_Regular' }]
                });
                // Then add INBOX which gets special use
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    // When sorting, INBOX has specialUse, AAA_Regular does not
    // So the comparison should hit: !a.specialUse && b.specialUse returns 1
    // This means INBOX should come first even though AAA_Regular is alphabetically first
    test.ok(result.length >= 2);
    test.equal(result[0].path, 'INBOX');
    test.equal(result[0].specialUse, '\\Inbox');
    test.done();
};

module.exports['Commands: list sort fallback path comparison'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['SPECIAL-USE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                // Create folders where parent parts match but paths differ at the end
                // A/B/C and A/B will have matching parts up to a point
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'Parent/Child/Deep' }]
                });
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'Parent/Child' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*');
    // Parent/Child should come before Parent/Child/Deep
    const childIndex = result.findIndex(e => e.path === 'Parent/Child');
    const deepIndex = result.findIndex(e => e.path === 'Parent/Child/Deep');
    test.ok(childIndex < deepIndex, 'Shorter path should sort before longer when parent matches');
    test.done();
};

module.exports['Commands: list STATUS handles unknown key in response'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([
            ['SPECIAL-USE', true],
            ['LIST-STATUS', true]
        ]),
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged) {
                if (opts.untagged.LIST) {
                    await opts.untagged.LIST({
                        attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'TestFolder' }]
                    });
                }
                if (opts.untagged.STATUS) {
                    await opts.untagged.STATUS({
                        attributes: [{ value: 'TestFolder' }, [{ value: 'XUNKNOWN' }, { value: '999' }, { value: 'MESSAGES' }, { value: '10' }]]
                    });
                }
            }
            return { next: () => {} };
        }
    });

    const result = await listCommand(connection, '', '*', { statusQuery: { messages: true } });
    const folder = result.find(e => e.path === 'TestFolder');
    test.ok(folder);
    test.ok(folder.status);
    test.equal(folder.status.messages, 10);
    test.equal(folder.status.XUNKNOWN, undefined); // Unknown keys silently ignored
    test.done();
};

// ============================================
// SELECT Command Tests
// ============================================

const selectCommand = require('../lib/commands/select');

module.exports['Commands: select basic'] = async test => {
    let execCalled = false;
    let execCommand = '';
    const connection = createMockConnection({
        state: 2, // AUTHENTICATED
        folders: new Map([['INBOX', { path: 'INBOX', delimiter: '/' }]]),
        run: async () => [],
        exec: async (cmd, attrs, opts) => {
            execCalled = true;
            execCommand = cmd;
            // Simulate SELECT response
            if (opts && opts.untagged) {
                if (opts.untagged.FLAGS) {
                    await opts.untagged.FLAGS({
                        attributes: [[{ value: '\\Seen' }, { value: '\\Answered' }, { value: '\\Flagged' }]]
                    });
                }
                if (opts.untagged.EXISTS) {
                    await opts.untagged.EXISTS({ command: '100' });
                }
                if (opts.untagged.OK) {
                    await opts.untagged.OK({
                        attributes: [{ section: [{ type: 'ATOM', value: 'UIDVALIDITY' }, { value: '12345' }] }]
                    });
                    await opts.untagged.OK({
                        attributes: [{ section: [{ type: 'ATOM', value: 'UIDNEXT' }, { value: '1000' }] }]
                    });
                    await opts.untagged.OK({
                        attributes: [{ section: [{ type: 'ATOM', value: 'PERMANENTFLAGS' }, [{ value: '\\*' }]] }]
                    });
                }
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX');
    test.equal(execCalled, true);
    test.equal(execCommand, 'SELECT');
    test.ok(result);
    test.equal(result.path, 'INBOX');
    test.equal(result.exists, 100);
    test.equal(result.readOnly, false);
    test.done();
};

module.exports['Commands: select with readOnly option uses EXAMINE'] = async test => {
    let execCommand = '';
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async cmd => {
            execCommand = cmd;
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-ONLY' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX', { readOnly: true });
    test.equal(execCommand, 'EXAMINE');
    test.equal(result.readOnly, true);
    test.done();
};

module.exports['Commands: select skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 }); // NOT_AUTHENTICATED

    const result = await selectCommand(connection, 'INBOX');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: select fetches folder list if not cached'] = async test => {
    let listCalled = false;
    const connection = createMockConnection({
        state: 2,
        folders: new Map(), // Empty - will trigger LIST
        run: async cmd => {
            if (cmd === 'LIST') {
                listCalled = true;
                return [{ path: 'INBOX', delimiter: '/' }];
            }
        },
        exec: async () => ({
            next: () => {},
            response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
        }),
        emit: () => {}
    });

    await selectCommand(connection, 'INBOX');
    test.equal(listCalled, true);
    test.done();
};

module.exports['Commands: select throws when LIST fails'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map(),
        run: async () => null // LIST returns null
    });

    try {
        await selectCommand(connection, 'INBOX');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.message, 'Failed to fetch folders');
    }
    test.done();
};

module.exports['Commands: select with QRESYNC'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 2,
        enabled: new Set(['QRESYNC']),
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async (cmd, attrs, opts) => {
            execAttrs = attrs;
            // Must return matching UIDVALIDITY and HIGHESTMODSEQ for QRESYNC to remain valid
            if (opts && opts.untagged && opts.untagged.OK) {
                await opts.untagged.OK({
                    attributes: [{ section: [{ type: 'ATOM', value: 'UIDVALIDITY' }, { value: '67890' }] }]
                });
                await opts.untagged.OK({
                    attributes: [{ section: [{ type: 'ATOM', value: 'HIGHESTMODSEQ' }, { value: '100' }] }]
                });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {},
        untaggedVanished: async () => {},
        untaggedFetch: async () => {}
    });

    const result = await selectCommand(connection, 'INBOX', {
        changedSince: '12345',
        uidValidity: BigInt(67890)
    });
    test.ok(execAttrs);
    const attrsStr = JSON.stringify(execAttrs);
    test.ok(attrsStr.includes('QRESYNC'));
    test.equal(result.qresync, true);
    test.done();
};

module.exports['Commands: select QRESYNC invalidated when UIDVALIDITY mismatch'] = async test => {
    const connection = createMockConnection({
        state: 2,
        enabled: new Set(['QRESYNC']),
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async (cmd, attrs, opts) => {
            // Return different UIDVALIDITY
            if (opts && opts.untagged && opts.untagged.OK) {
                await opts.untagged.OK({
                    attributes: [{ section: [{ type: 'ATOM', value: 'UIDVALIDITY' }, { value: '99999' }] }]
                });
                await opts.untagged.OK({
                    attributes: [{ section: [{ type: 'ATOM', value: 'HIGHESTMODSEQ' }, { value: '100' }] }]
                });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX', {
        changedSince: '12345',
        uidValidity: BigInt(67890) // Different from server's 99999
    });
    // QRESYNC should be invalidated due to UIDVALIDITY mismatch
    test.equal(result.qresync, false);
    test.done();
};

module.exports['Commands: select QRESYNC invalidated when NOMODSEQ'] = async test => {
    const connection = createMockConnection({
        state: 2,
        enabled: new Set(['QRESYNC']),
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.OK) {
                await opts.untagged.OK({
                    attributes: [{ section: [{ type: 'ATOM', value: 'UIDVALIDITY' }, { value: '67890' }] }]
                });
                // NOMODSEQ present
                await opts.untagged.OK({
                    attributes: [{ section: [{ type: 'ATOM', value: 'NOMODSEQ' }] }]
                });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX', {
        changedSince: '12345',
        uidValidity: BigInt(67890)
    });
    test.equal(result.noModseq, true);
    test.equal(result.qresync, false);
    test.done();
};

module.exports['Commands: select parses HIGHESTMODSEQ'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.OK) {
                await opts.untagged.OK({
                    attributes: [{ section: [{ type: 'ATOM', value: 'HIGHESTMODSEQ' }, { value: '9876543210' }] }]
                });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX');
    test.equal(result.highestModseq, BigInt('9876543210'));
    test.done();
};

module.exports['Commands: select parses MAILBOXID'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.OK) {
                await opts.untagged.OK({
                    attributes: [{ section: [{ type: 'ATOM', value: 'MAILBOXID' }, [{ value: 'abc123' }]] }]
                });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX');
    test.equal(result.mailboxId, 'abc123');
    test.done();
};

module.exports['Commands: select emits mailboxOpen event'] = async test => {
    let emittedEvents = [];
    const connection = createMockConnection({
        state: 2,
        mailbox: false, // No current mailbox
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async () => ({
            next: () => {},
            response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
        }),
        emit: event => {
            emittedEvents.push(event);
        }
    });

    await selectCommand(connection, 'INBOX');
    test.ok(emittedEvents.includes('mailboxOpen'));
    test.done();
};

module.exports['Commands: select emits mailboxClose when switching'] = async test => {
    let emittedEvents = [];
    const connection = createMockConnection({
        state: 3, // Already SELECTED
        mailbox: { path: 'OldFolder' },
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async () => ({
            next: () => {},
            response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
        }),
        emit: event => {
            emittedEvents.push(event);
        }
    });

    await selectCommand(connection, 'INBOX');
    test.ok(emittedEvents.includes('mailboxClose'));
    test.ok(emittedEvents.includes('mailboxOpen'));
    test.done();
};

module.exports['Commands: select handles error'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async () => {
            const err = new Error('Select failed');
            err.response = { attributes: [] };
            throw err;
        },
        emit: () => {}
    });

    try {
        await selectCommand(connection, 'INBOX');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.message, 'Select failed');
    }
    test.done();
};

module.exports['Commands: select resets state on error when SELECTED'] = async test => {
    let emittedEvent = '';
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'CurrentFolder' },
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async () => {
            const err = new Error('Select failed');
            err.response = { attributes: [] };
            throw err;
        },
        emit: event => {
            emittedEvent = event;
        }
    });

    try {
        await selectCommand(connection, 'INBOX');
    } catch (err) {
        // Expected - error is intentionally ignored
        err.expected = true;
    }
    test.equal(connection.state, 2); // Reset to AUTHENTICATED
    test.equal(connection.mailbox, false);
    test.equal(emittedEvent, 'mailboxClose');
    test.done();
};

module.exports['Commands: select copies folder metadata'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map([
            [
                'INBOX',
                {
                    path: 'INBOX',
                    delimiter: '/',
                    specialUse: '\\Inbox',
                    subscribed: true,
                    listed: true
                }
            ]
        ]),
        run: async () => [],
        exec: async () => ({
            next: () => {},
            response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
        }),
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX');
    test.equal(result.delimiter, '/');
    test.equal(result.specialUse, '\\Inbox');
    test.equal(result.subscribed, true);
    test.equal(result.listed, true);
    test.done();
};

module.exports['Commands: select handles VANISHED untagged'] = async test => {
    let vanishedCalled = false;
    const connection = createMockConnection({
        state: 2,
        enabled: new Set(['QRESYNC']),
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.VANISHED) {
                await opts.untagged.VANISHED({ attributes: [] });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {},
        untaggedVanished: async () => {
            vanishedCalled = true;
        }
    });

    await selectCommand(connection, 'INBOX', { changedSince: '100', uidValidity: BigInt(123) });
    test.equal(vanishedCalled, true);
    test.done();
};

module.exports['Commands: select handles FETCH untagged'] = async test => {
    let fetchCalled = false;
    const connection = createMockConnection({
        state: 2,
        enabled: new Set(['QRESYNC']),
        folders: new Map([['INBOX', { path: 'INBOX' }]]),
        run: async () => [],
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.FETCH) {
                await opts.untagged.FETCH({ command: '1', attributes: [] });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {},
        untaggedFetch: async () => {
            fetchCalled = true;
        }
    });

    await selectCommand(connection, 'INBOX', { changedSince: '100', uidValidity: BigInt(123) });
    test.equal(fetchCalled, true);
    test.done();
};

module.exports['Commands: select encodes path with special characters'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['Test&Folder', { path: 'Test&Folder' }]]),
        run: async () => [],
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    await selectCommand(connection, 'Test&Folder');
    // Path with & should use STRING type instead of ATOM
    test.ok(execAttrs);
    test.equal(execAttrs[0].type, 'STRING');
    test.done();
};

module.exports['Commands: select handles empty OK attributes'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['INBOX', { path: 'INBOX', delimiter: '/' }]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.OK) {
                // Empty attributes - should return early
                await opts.untagged.OK({
                    attributes: []
                });
            }
            if (opts && opts.untagged && opts.untagged.EXISTS) {
                await opts.untagged.EXISTS({ command: '100' });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX');
    test.ok(result);
    test.done();
};

module.exports['Commands: select handles null FLAGS attributes'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['INBOX', { path: 'INBOX', delimiter: '/' }]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.FLAGS) {
                // Null/undefined attributes - should return early
                await opts.untagged.FLAGS({
                    attributes: null
                });
            }
            if (opts && opts.untagged && opts.untagged.EXISTS) {
                await opts.untagged.EXISTS({ command: '100' });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX');
    test.ok(result);
    test.equal(result.flags, undefined);
    test.done();
};

module.exports['Commands: select handles NaN EXISTS'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['INBOX', { path: 'INBOX', delimiter: '/' }]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.EXISTS) {
                // NaN command value - should return false
                await opts.untagged.EXISTS({ command: 'invalid' });
            }
            return {
                next: () => {},
                response: { attributes: [{ section: [{ type: 'ATOM', value: 'READ-WRITE' }] }] }
            };
        },
        emit: () => {}
    });

    const result = await selectCommand(connection, 'INBOX');
    test.ok(result);
    test.equal(result.exists, undefined);
    test.done();
};

module.exports['Commands: select error with serverResponseCode'] = async test => {
    const connection = createMockConnection({
        state: 2,
        folders: new Map([['INBOX', { path: 'INBOX', delimiter: '/' }]]),
        exec: async () => {
            const err = new Error('Select failed');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'NONEXISTENT' }]
                    },
                    { type: 'TEXT', value: 'Mailbox does not exist' }
                ]
            };
            throw err;
        },
        emit: () => {}
    });

    try {
        await selectCommand(connection, 'INBOX');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.serverResponseCode, 'NONEXISTENT');
    }
    test.done();
};

// ============================================
// STATUS Command Tests
// ============================================

const statusCommand = require('../lib/commands/status');

module.exports['Commands: status basic'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 2, // AUTHENTICATED
        exec: async (cmd, attrs, opts) => {
            execCalled = true;
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [{ value: 'INBOX' }, [{ value: 'MESSAGES' }, { value: '100' }, { value: 'UNSEEN' }, { value: '10' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'INBOX', { messages: true, unseen: true });
    test.equal(execCalled, true);
    test.ok(result);
    test.equal(result.path, 'INBOX');
    test.equal(result.messages, 100);
    test.equal(result.unseen, 10);
    test.done();
};

module.exports['Commands: status skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 }); // NOT_AUTHENTICATED

    const result = await statusCommand(connection, 'INBOX', { messages: true });
    test.equal(result, false);
    test.done();
};

module.exports['Commands: status skips when no path'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await statusCommand(connection, '', { messages: true });
    test.equal(result, false);
    test.done();
};

module.exports['Commands: status skips when no query attributes'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await statusCommand(connection, 'INBOX', {});
    test.equal(result, false);
    test.done();
};

module.exports['Commands: status skips when all query values are false'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await statusCommand(connection, 'INBOX', { messages: false, unseen: false });
    test.equal(result, false);
    test.done();
};

module.exports['Commands: status with all standard query attributes'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs, opts) => {
            queryAttrs = attrs;
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [
                        { value: 'INBOX' },
                        [
                            { value: 'MESSAGES' },
                            { value: '100' },
                            { value: 'RECENT' },
                            { value: '5' },
                            { value: 'UIDNEXT' },
                            { value: '1000' },
                            { value: 'UIDVALIDITY' },
                            { value: '12345' },
                            { value: 'UNSEEN' },
                            { value: '10' }
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'INBOX', {
        messages: true,
        recent: true,
        uidNext: true,
        uidValidity: true,
        unseen: true
    });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('MESSAGES'));
    test.ok(queryStr.includes('RECENT'));
    test.ok(queryStr.includes('UIDNEXT'));
    test.ok(queryStr.includes('UIDVALIDITY'));
    test.ok(queryStr.includes('UNSEEN'));

    test.equal(result.messages, 100);
    test.equal(result.recent, 5);
    test.equal(result.uidNext, 1000);
    test.equal(result.uidValidity, BigInt(12345));
    test.equal(result.unseen, 10);
    test.done();
};

module.exports['Commands: status with HIGHESTMODSEQ and CONDSTORE'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['CONDSTORE', true]]),
        exec: async (cmd, attrs, opts) => {
            queryAttrs = attrs;
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [{ value: 'INBOX' }, [{ value: 'HIGHESTMODSEQ' }, { value: '9876543210' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'INBOX', { highestModseq: true });
    test.ok(queryAttrs);
    const queryStr = JSON.stringify(queryAttrs);
    test.ok(queryStr.includes('HIGHESTMODSEQ'));
    test.equal(result.highestModseq, BigInt('9876543210'));
    test.done();
};

module.exports['Commands: status ignores HIGHESTMODSEQ without CONDSTORE'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map(), // No CONDSTORE
        exec: async () => ({ next: () => {} })
    });

    const result = await statusCommand(connection, 'INBOX', { highestModseq: true });
    // Should return false since no valid query attributes
    test.equal(result, false);
    test.done();
};

module.exports['Commands: status updates current mailbox when SELECTED'] = async test => {
    let existsEmitted = false;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'INBOX', exists: 50, uidNext: 500 },
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [{ value: 'INBOX' }, [{ value: 'MESSAGES' }, { value: '100' }, { value: 'UIDNEXT' }, { value: '1000' }]]
                });
            }
            return { next: () => {} };
        },
        emit: event => {
            if (event === 'exists') existsEmitted = true;
        }
    });

    await statusCommand(connection, 'INBOX', { messages: true, uidNext: true });
    // Mailbox should be updated
    test.equal(connection.mailbox.exists, 100);
    test.equal(connection.mailbox.uidNext, 1000);
    // exists event should be emitted since count changed
    test.equal(existsEmitted, true);
    test.done();
};

module.exports['Commands: status does not emit exists when count unchanged'] = async test => {
    let existsEmitted = false;
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX', exists: 100 }, // Same as response
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [{ value: 'INBOX' }, [{ value: 'MESSAGES' }, { value: '100' }]]
                });
            }
            return { next: () => {} };
        },
        emit: event => {
            if (event === 'exists') existsEmitted = true;
        }
    });

    await statusCommand(connection, 'INBOX', { messages: true });
    test.equal(existsEmitted, false);
    test.done();
};

module.exports['Commands: status handles error with NO response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        run: async () => [], // LIST returns empty - folder doesn't exist
        exec: async () => {
            const err = new Error('Mailbox not found');
            err.responseStatus = 'NO';
            throw err;
        }
    });

    try {
        await statusCommand(connection, 'NonExistent', { messages: true });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.code, 'NotFound');
    }
    test.done();
};

module.exports['Commands: status returns false on other errors'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Some error');
            err.responseStatus = 'BAD';
            throw err;
        }
    });

    const result = await statusCommand(connection, 'INBOX', { messages: true });
    test.equal(result, false);
    test.done();
};

module.exports['Commands: status handles empty STATUS response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                // Empty list - should be ignored
                await opts.untagged.STATUS({
                    attributes: [{ value: 'INBOX' }, false]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'INBOX', { messages: true });
    test.ok(result);
    test.equal(result.path, 'INBOX');
    // No messages property since response was empty
    test.equal(result.messages, undefined);
    test.done();
};

module.exports['Commands: status handles invalid entry values'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [
                        { value: 'INBOX' },
                        [
                            { value: 'MESSAGES' },
                            { value: 'not-a-number' },
                            { value: 'UNSEEN' },
                            { value: '10' },
                            null,
                            { value: '5' }, // Invalid key
                            { value: 'RECENT' },
                            null // Invalid value
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'INBOX', { messages: true, unseen: true, recent: true });
    test.ok(result);
    // MESSAGES with invalid value should be skipped (isNaN check fails)
    test.equal(result.messages, undefined);
    // UNSEEN should work
    test.equal(result.unseen, 10);
    // RECENT with null value should be skipped
    test.equal(result.recent, undefined);
    test.done();
};

module.exports['Commands: status encodes path with special characters'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return { next: () => {} };
        }
    });

    await statusCommand(connection, 'Test&Folder', { messages: true });
    // Path with & should use STRING type instead of ATOM
    test.ok(execAttrs);
    test.equal(execAttrs[0].type, 'STRING');
    test.done();
};

module.exports['Commands: status works from SELECTED state'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'OtherFolder' }, // Different folder
        exec: async (cmd, attrs, opts) => {
            execCalled = true;
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [{ value: 'INBOX' }, [{ value: 'MESSAGES' }, { value: '50' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'INBOX', { messages: true });
    test.equal(execCalled, true);
    test.equal(result.messages, 50);
    test.done();
};

module.exports['Commands: status updates HIGHESTMODSEQ for current mailbox'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['CONDSTORE', true]]),
        mailbox: { path: 'INBOX', highestModseq: BigInt(100) },
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [{ value: 'INBOX' }, [{ value: 'HIGHESTMODSEQ' }, { value: '200' }]]
                });
            }
            return { next: () => {} };
        }
    });

    await statusCommand(connection, 'INBOX', { highestModseq: true });
    test.equal(connection.mailbox.highestModseq, BigInt(200));
    test.done();
};

module.exports['Commands: status handles NaN values in response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [
                        { value: 'TestFolder' },
                        [
                            { value: 'MESSAGES' },
                            { value: 'invalid' }, // NaN
                            { value: 'RECENT' },
                            { value: 'notanumber' }, // NaN
                            { value: 'UIDNEXT' },
                            { value: 'abc' }, // NaN
                            { value: 'UIDVALIDITY' },
                            { value: 'xyz' }, // NaN
                            { value: 'UNSEEN' },
                            { value: 'bad' } // NaN
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'TestFolder', {
        messages: true,
        recent: true,
        uidNext: true,
        uidValidity: true,
        unseen: true
    });
    test.ok(result);
    test.equal(result.path, 'TestFolder');
    // NaN values should not be set
    test.equal(result.messages, undefined);
    test.equal(result.recent, undefined);
    test.equal(result.uidNext, undefined);
    test.equal(result.uidValidity, undefined);
    test.equal(result.unseen, undefined);
    test.done();
};

module.exports['Commands: status handles NaN HIGHESTMODSEQ'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['CONDSTORE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [{ value: 'TestFolder' }, [{ value: 'HIGHESTMODSEQ' }, { value: 'notvalid' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'TestFolder', { highestModseq: true });
    test.ok(result);
    test.equal(result.highestModseq, undefined);
    test.done();
};

module.exports['Commands: status filters falsy query values'] = async test => {
    let queryAttrs = null;
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs) => {
            queryAttrs = attrs;
            return { next: () => {} };
        }
    });

    // Mix of truthy and falsy values
    const result = await statusCommand(connection, 'TestFolder', {
        messages: true,
        recent: false, // Should be filtered
        uidNext: 0, // Falsy, should be filtered
        uidValidity: true,
        unseen: null // Falsy, should be filtered
    });
    test.ok(result);
    // Query should only include messages and uidValidity
    test.ok(queryAttrs);
    const queryList = queryAttrs[1];
    test.equal(queryList.length, 2);
    test.done();
};

module.exports['Commands: status handles missing entry value'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [
                        { value: 'TestFolder' },
                        [
                            { value: 'MESSAGES' },
                            null, // Missing value
                            { value: 'RECENT' },
                            { value: '5' }
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'TestFolder', {
        messages: true,
        recent: true
    });
    test.ok(result);
    test.equal(result.messages, undefined); // Skipped due to null value
    test.equal(result.recent, 5);
    test.done();
};

module.exports['Commands: status handles missing key in response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [
                        { value: 'TestFolder' },
                        [
                            null, // Missing key
                            { value: '10' },
                            { value: 'MESSAGES' },
                            { value: '20' }
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'TestFolder', { messages: true });
    test.ok(result);
    test.equal(result.messages, 20);
    test.done();
};

module.exports['Commands: status handles unknown key in response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.STATUS) {
                await opts.untagged.STATUS({
                    attributes: [{ value: 'TestFolder' }, [{ value: 'UNKNOWNKEY' }, { value: '999' }, { value: 'MESSAGES' }, { value: '10' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await statusCommand(connection, 'TestFolder', { messages: true });
    test.ok(result);
    test.equal(result.messages, 10);
    test.equal(result.UNKNOWNKEY, undefined); // Unknown keys ignored
    test.done();
};

// ============================================
// APPEND Command Tests
// ============================================

const appendCommand = require('../lib/commands/append');

module.exports['Commands: append basic'] = async test => {
    let appendCalled = false;
    const connection = createMockConnection({
        state: 2, // AUTHENTICATED
        mailbox: { path: 'OtherFolder' }, // Different folder to avoid EXISTS handling
        exec: async cmd => {
            if (cmd === 'APPEND') {
                appendCalled = true;
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    const result = await appendCommand(connection, 'INBOX', 'Test message content');
    test.equal(appendCalled, true);
    test.ok(result);
    test.equal(result.destination, 'INBOX');
    test.done();
};

module.exports['Commands: append with Buffer content'] = async test => {
    let contentAttr = null;
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'OtherFolder' },
        exec: async (cmd, attrs) => {
            if (cmd === 'APPEND' && Array.isArray(attrs)) {
                contentAttr = attrs.find(a => a && a.type === 'LITERAL');
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    const buffer = Buffer.from('Test message');
    await appendCommand(connection, 'INBOX', buffer);
    test.ok(contentAttr);
    test.ok(Buffer.isBuffer(contentAttr.value));
    test.equal(contentAttr.value.toString(), 'Test message');
    test.done();
};

module.exports['Commands: append skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 }); // NOT_AUTHENTICATED

    const result = await appendCommand(connection, 'INBOX', 'content');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: append skips when no destination'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await appendCommand(connection, '', 'content');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: append with flags'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'OtherFolder', permanentFlags: new Set(['\\*']) },
        exec: async (cmd, attrs) => {
            if (cmd === 'APPEND' && Array.isArray(attrs)) {
                execAttrs = attrs;
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    await appendCommand(connection, 'INBOX', 'content', ['\\Seen', '\\Flagged']);
    test.ok(execAttrs);
    // Should have flags array between path and content
    const flagsAttr = execAttrs.find(a => Array.isArray(a));
    test.ok(flagsAttr);
    test.ok(flagsAttr.some(f => f.value === '\\Seen'));
    test.ok(flagsAttr.some(f => f.value === '\\Flagged'));
    test.done();
};

module.exports['Commands: append with internal date'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'OtherFolder' },
        exec: async (cmd, attrs) => {
            if (cmd === 'APPEND' && Array.isArray(attrs)) {
                execAttrs = attrs;
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    const date = new Date('2024-01-15T10:30:00Z');
    await appendCommand(connection, 'INBOX', 'content', [], date);
    test.ok(execAttrs);
    // Should have date string
    const dateAttr = execAttrs.find(a => a && a.type === 'STRING');
    test.ok(dateAttr);
    test.ok(dateAttr.value.includes('2024'));
    test.done();
};

module.exports['Commands: append checks APPENDLIMIT'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['APPENDLIMIT', 100]]), // 100 byte limit
        mailbox: { path: 'INBOX' }
    });

    const largeContent = Buffer.alloc(200, 'x'); // 200 bytes, exceeds limit

    try {
        await appendCommand(connection, 'INBOX', largeContent);
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.serverResponseCode, 'APPENDLIMIT');
        test.ok(err.message.includes('APPENDLIMIT'));
    }
    test.done();
};

module.exports['Commands: append allows content within APPENDLIMIT'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['APPENDLIMIT', 1000]]),
        mailbox: { path: 'INBOX' },
        exec: async () => {
            execCalled = true;
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    const content = Buffer.alloc(500, 'x'); // Within limit
    await appendCommand(connection, 'INBOX', content);
    test.equal(execCalled, true);
    test.done();
};

module.exports['Commands: append with APPENDUID response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'INBOX' },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [
                            { value: 'APPENDUID' },
                            { value: '12345' }, // uidValidity
                            { value: '100' } // uid
                        ]
                    }
                ]
            }
        })
    });

    const result = await appendCommand(connection, 'INBOX', 'content');
    test.equal(result.uidValidity, BigInt(12345));
    test.equal(result.uid, 100);
    test.done();
};

module.exports['Commands: append to current mailbox triggers EXISTS'] = async test => {
    let existsEmitted = false;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'INBOX', exists: 10 },
        exec: async (cmd, attrs, opts) => {
            // Simulate EXISTS untagged response
            if (cmd === 'APPEND' && opts && opts.untagged && opts.untagged.EXISTS) {
                await opts.untagged.EXISTS({ command: '11' });
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        },
        emit: event => {
            if (event === 'exists') existsEmitted = true;
        },
        search: async () => [100] // Return UID
    });

    await appendCommand(connection, 'INBOX', 'content');
    test.equal(existsEmitted, true);
    test.equal(connection.mailbox.exists, 11);
    test.done();
};

module.exports['Commands: append runs NOOP to get sequence if not in EXISTS'] = async test => {
    let noopCalled = false;
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX', exists: 10 },
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'NOOP') {
                noopCalled = true;
                if (opts && opts.untagged && opts.untagged.EXISTS) {
                    await opts.untagged.EXISTS({ command: '11' });
                }
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        },
        emit: () => {},
        search: async () => [100] // Return UID
    });

    const result = await appendCommand(connection, 'INBOX', 'content');
    test.equal(noopCalled, true);
    test.equal(result.seq, 11);
    test.done();
};

module.exports['Commands: append searches for UID if seq but no uid'] = async test => {
    let searchCalled = false;
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX', exists: 10 },
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.untagged && opts.untagged.EXISTS) {
                await opts.untagged.EXISTS({ command: '11' });
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        },
        emit: () => {},
        search: async () => {
            searchCalled = true;
            return [100];
        }
    });

    const result = await appendCommand(connection, 'INBOX', 'content');
    test.equal(searchCalled, true);
    test.equal(result.uid, 100);
    test.done();
};

module.exports['Commands: append with BINARY and NULL bytes'] = async test => {
    let literalAttr = null;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['BINARY', true]]),
        mailbox: { path: 'INBOX' },
        exec: async (cmd, attrs) => {
            literalAttr = attrs.find(a => a.type === 'LITERAL');
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    // Content with NULL byte
    const content = Buffer.concat([Buffer.from('test'), Buffer.from([0]), Buffer.from('data')]);
    await appendCommand(connection, 'INBOX', content);
    test.ok(literalAttr);
    test.equal(literalAttr.isLiteral8, true);
    test.done();
};

module.exports['Commands: append without BINARY uses regular literal'] = async test => {
    let literalAttr = null;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map(), // No BINARY
        mailbox: { path: 'INBOX' },
        exec: async (cmd, attrs) => {
            literalAttr = attrs.find(a => a.type === 'LITERAL');
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    const content = Buffer.concat([Buffer.from('test'), Buffer.from([0]), Buffer.from('data')]);
    await appendCommand(connection, 'INBOX', content);
    test.ok(literalAttr);
    test.equal(literalAttr.isLiteral8, false);
    test.done();
};

module.exports['Commands: append handles error'] = async test => {
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'OtherFolder' },
        exec: async () => {
            const err = new Error('Append failed');
            err.response = { attributes: [] };
            throw err;
        }
    });

    try {
        await appendCommand(connection, 'INBOX', 'content');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.message, 'Append failed');
    }
    test.done();
};

module.exports['Commands: append filters invalid flags'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 2,
        mailbox: {
            path: 'OtherFolder',
            permanentFlags: new Set(['\\Seen', '\\Flagged']) // Only allow these
        },
        exec: async (cmd, attrs) => {
            if (cmd === 'APPEND' && Array.isArray(attrs)) {
                execAttrs = attrs;
            }
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    // Mix of valid and invalid flags
    await appendCommand(connection, 'INBOX', 'content', ['\\Seen', '\\CustomFlag', null, '\\Flagged']);
    test.ok(execAttrs);
    const flagsAttr = execAttrs.find(a => Array.isArray(a));
    test.ok(flagsAttr);
    // Should only contain allowed flags
    test.equal(flagsAttr.length, 2);
    test.done();
};

module.exports['Commands: append works from SELECTED state'] = async test => {
    let execCalled = false;
    const connection = createMockConnection({
        state: 3, // SELECTED
        mailbox: { path: 'OtherFolder', exists: 10 },
        exec: async () => {
            execCalled = true;
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    // Append to different folder than current
    const result = await appendCommand(connection, 'INBOX', 'content');
    test.equal(execCalled, true);
    test.equal(result.destination, 'INBOX');
    test.done();
};

module.exports['Commands: append error with serverResponseCode'] = async test => {
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'OtherFolder' },
        exec: async () => {
            const err = new Error('Append failed');
            err.response = {
                tag: '*',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'TRYCREATE' }]
                    },
                    { type: 'TEXT', value: 'Mailbox does not exist' }
                ]
            };
            throw err;
        }
    });

    try {
        await appendCommand(connection, 'NonExistent', 'content');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.serverResponseCode, 'TRYCREATE');
    }
    test.done();
};

module.exports['Commands: append with invalid APPENDUID values'] = async test => {
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'OtherFolder' },
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        type: 'ATOM',
                        section: [
                            { type: 'ATOM', value: 'APPENDUID' },
                            { type: 'ATOM', value: 'invalid' }, // Invalid uidValidity
                            { type: 'ATOM', value: 'notanumber' } // Invalid uid
                        ]
                    }
                ]
            }
        })
    });

    const result = await appendCommand(connection, 'INBOX', 'content');
    test.ok(result);
    test.equal(result.uidValidity, undefined);
    test.equal(result.uid, undefined);
    test.done();
};

module.exports['Commands: append NOOP error is caught'] = async test => {
    let noopCalled = false;
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX', exists: 10 },
        exec: async cmd => {
            if (cmd === 'APPEND') {
                return {
                    next: () => {},
                    response: { attributes: [] }
                };
            }
            if (cmd === 'NOOP') {
                noopCalled = true;
                const err = new Error('NOOP failed');
                err.response = { attributes: [] };
                throw err;
            }
        }
    });

    // Append to current mailbox, expectExists = true
    const result = await appendCommand(connection, 'INBOX', 'content');
    test.ok(result);
    test.equal(noopCalled, true);
    // Should not throw, NOOP error is caught
    test.done();
};

module.exports['Commands: append EXISTS updates mailbox count'] = async test => {
    let emittedEvent = null;
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX', exists: 10 },
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'APPEND' && opts && opts.untagged && opts.untagged.EXISTS) {
                await opts.untagged.EXISTS({ command: '11' }); // New count
            }
            return {
                next: () => {},
                response: {
                    attributes: [
                        {
                            type: 'ATOM',
                            section: [
                                { type: 'ATOM', value: 'APPENDUID' },
                                { type: 'ATOM', value: '12345' },
                                { type: 'ATOM', value: '100' }
                            ]
                        }
                    ]
                }
            };
        },
        emit: (event, data) => {
            if (event === 'exists') {
                emittedEvent = data;
            }
        }
    });

    const result = await appendCommand(connection, 'INBOX', 'content');
    test.ok(result);
    test.equal(result.seq, 11);
    test.equal(connection.mailbox.exists, 11);
    test.ok(emittedEvent);
    test.equal(emittedEvent.count, 11);
    test.equal(emittedEvent.prevCount, 10);
    test.done();
};

module.exports['Commands: append does not emit exists when count unchanged'] = async test => {
    let emittedEvent = null;
    const connection = createMockConnection({
        state: 3,
        mailbox: { path: 'INBOX', exists: 10 },
        exec: async (cmd, attrs, opts) => {
            if (cmd === 'APPEND' && opts && opts.untagged && opts.untagged.EXISTS) {
                await opts.untagged.EXISTS({ command: '10' }); // Same count
            }
            return {
                next: () => {},
                response: {
                    attributes: [
                        {
                            type: 'ATOM',
                            section: [
                                { type: 'ATOM', value: 'APPENDUID' },
                                { type: 'ATOM', value: '12345' },
                                { type: 'ATOM', value: '100' }
                            ]
                        }
                    ]
                }
            };
        },
        emit: (event, data) => {
            if (event === 'exists') {
                emittedEvent = data;
            }
        }
    });

    await appendCommand(connection, 'INBOX', 'content');
    test.equal(emittedEvent, null); // No event emitted
    test.done();
};

module.exports['Commands: append with both flags and date'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'OtherFolder' },
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    const testDate = new Date('2024-01-15T10:30:00Z');
    await appendCommand(connection, 'INBOX', 'content', ['\\Seen'], testDate);
    test.ok(execAttrs);
    // Should have: path, flags array, date string, literal
    test.equal(execAttrs.length, 4);
    // Flags array
    test.ok(Array.isArray(execAttrs[1]));
    // Date string
    test.equal(execAttrs[2].type, 'STRING');
    test.done();
};

module.exports['Commands: append with disableBinary does not use literal8'] = async test => {
    let execAttrs = null;
    const connection = createMockConnection({
        state: 2,
        mailbox: { path: 'OtherFolder' },
        capabilities: new Map([['BINARY', true]]),
        disableBinary: true,
        exec: async (cmd, attrs) => {
            execAttrs = attrs;
            return {
                next: () => {},
                response: { attributes: [] }
            };
        }
    });

    // Content with NULL byte
    const content = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x57, 0x6f, 0x72, 0x6c, 0x64]);
    await appendCommand(connection, 'INBOX', content);
    test.ok(execAttrs);
    const literalAttr = execAttrs.find(a => a && a.type === 'LITERAL');
    test.ok(literalAttr);
    test.equal(literalAttr.isLiteral8, false); // Not literal8 due to disableBinary
    test.done();
};

// ============================================
// IDLE Command Tests
// ============================================

const idleCommand = require('../lib/commands/idle');

module.exports['Commands: idle with IDLE capability'] = async test => {
    let execCommand = '';
    let idlingSet = false;
    const connection = createMockConnection({
        state: 3, // SELECTED
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            execCommand = cmd;
            idlingSet = connection.idling;
            // Simulate continuation response
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            return { next: () => {} };
        },
        write: () => {}
    });

    await idleCommand(connection);
    test.equal(execCommand, 'IDLE');
    test.equal(idlingSet, true);
    test.done();
};

module.exports['Commands: idle skips when not selected'] = async test => {
    const connection = createMockConnection({ state: 2 }); // AUTHENTICATED

    const result = await idleCommand(connection);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: idle falls back to NOOP without IDLE capability'] = async test => {
    let noopCalled = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(), // No IDLE
        currentSelectCommand: { command: 'SELECT', arguments: [{ value: 'INBOX' }] },
        exec: async cmd => {
            if (cmd === 'NOOP') {
                noopCalled = true;
                // Break out of the loop by calling preCheck
                if (connection.preCheck) {
                    await connection.preCheck();
                }
            }
            return { next: () => {} };
        }
    });

    // Start idle - it will loop with NOOP
    const idlePromise = idleCommand(connection);

    // Give it a moment to start, then break the loop
    await new Promise(resolve => setTimeout(resolve, 10));
    if (connection.preCheck) {
        await connection.preCheck();
    }

    await idlePromise;
    test.equal(noopCalled, true);
    test.done();
};

module.exports['Commands: idle preCheck breaks IDLE'] = async test => {
    let doneSent = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // After IDLE is initiated, trigger preCheck
            if (connection.preCheck) {
                await connection.preCheck();
            }
            return { next: () => {} };
        },
        write: data => {
            if (data === 'DONE') {
                doneSent = true;
            }
        }
    });

    await idleCommand(connection);
    test.equal(doneSent, true);
    test.equal(connection.idling, false);
    test.done();
};

module.exports['Commands: idle handles error'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async () => {
            throw new Error('IDLE failed');
        }
    });

    const result = await idleCommand(connection);
    test.equal(result, false);
    test.equal(connection.idling, false);
    test.done();
};

module.exports['Commands: idle with maxIdleTime restarts loop'] = async test => {
    let idleCount = 0;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            idleCount++;
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // Break after second iteration
            if (idleCount >= 2 && connection.preCheck) {
                await connection.preCheck();
            }
            return { next: () => {} };
        },
        write: () => {}
    });

    // Very short maxIdleTime to trigger restart
    await idleCommand(connection, 5);
    test.ok(idleCount >= 1);
    test.done();
};

module.exports['Commands: idle without currentSelectCommand returns immediately'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(), // No IDLE
        currentSelectCommand: false // No select command
    });

    // Should resolve immediately
    await idleCommand(connection);
    test.ok(true);
    test.done();
};

module.exports['Commands: idle NOOP fallback uses STATUS when configured'] = async test => {
    let statusCalled = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(),
        currentSelectCommand: { command: 'SELECT', arguments: [{ value: 'INBOX' }] },
        missingIdleCommand: 'STATUS',
        exec: async cmd => {
            if (cmd === 'STATUS') {
                statusCalled = true;
                if (connection.preCheck) {
                    await connection.preCheck();
                }
            }
            return { next: () => {} };
        }
    });

    await idleCommand(connection);
    test.equal(statusCalled, true);
    test.done();
};

module.exports['Commands: idle NOOP fallback uses SELECT when configured'] = async test => {
    let selectCalled = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(),
        currentSelectCommand: { command: 'SELECT', arguments: [{ value: 'INBOX' }] },
        missingIdleCommand: 'SELECT',
        exec: async cmd => {
            if (cmd === 'SELECT') {
                selectCalled = true;
                if (connection.preCheck) {
                    await connection.preCheck();
                }
            }
            return { next: () => {} };
        }
    });

    await idleCommand(connection);
    test.equal(selectCalled, true);
    test.done();
};

module.exports['Commands: idle sets preCheck function'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // Check that preCheck is set
            test.equal(typeof connection.preCheck, 'function');
            // Break the IDLE
            if (connection.preCheck) {
                await connection.preCheck();
            }
            return { next: () => {} };
        },
        write: () => {}
    });

    await idleCommand(connection);
    test.done();
};

module.exports['Commands: idle clears preCheck on completion'] = async test => {
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            if (connection.preCheck) {
                await connection.preCheck();
            }
            return { next: () => {} };
        },
        write: () => {}
    });

    await idleCommand(connection);
    test.equal(connection.preCheck, false);
    test.done();
};

module.exports['Commands: idle NOOP fallback handles error'] = async test => {
    let errorLogged = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map(),
        currentSelectCommand: { command: 'SELECT', arguments: [{ value: 'INBOX' }] },
        exec: async () => {
            throw new Error('NOOP failed');
        },
        log: {
            warn: () => {
                errorLogged = true;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    // Should resolve even on error
    await idleCommand(connection);
    test.equal(errorLogged, true);
    test.done();
};

module.exports['Commands: idle clears wait queue on normal completion'] = async test => {
    let preCheckResolved = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // Simulate waiting preCheck request before completion
            if (connection.preCheck) {
                // Queue a preCheck request
                connection.preCheck().then(() => {
                    preCheckResolved = true;
                });
            }
            return { next: () => {} };
        },
        write: () => {}
    });

    await idleCommand(connection);
    // Wait a tick for the promise to resolve
    await new Promise(resolve => setImmediate(resolve));
    test.equal(preCheckResolved, true);
    test.done();
};

module.exports['Commands: idle rejects wait queue on error'] = async test => {
    let preCheckRejected = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // Queue a preCheck request then throw
            if (connection.preCheck) {
                connection.preCheck().catch(() => {
                    preCheckRejected = true;
                });
            }
            throw new Error('IDLE failed');
        }
    });

    const result = await idleCommand(connection);
    test.equal(result, false);
    // Wait a tick for the promise to reject
    await new Promise(resolve => setImmediate(resolve));
    test.equal(preCheckRejected, true);
    test.done();
};

module.exports['Commands: idle onPlusTag calls preCheck if doneRequested'] = async test => {
    let doneSent = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            // Request done before onPlusTag is called
            if (connection.preCheck) {
                connection.preCheck().catch(() => {});
            }
            // Then call onPlusTag which should send DONE
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            return { next: () => {} };
        },
        write: data => {
            if (data === 'DONE') {
                doneSent = true;
            }
        }
    });

    await idleCommand(connection);
    test.equal(doneSent, true);
    test.done();
};

module.exports['Commands: idle calls onSend callback'] = async test => {
    let onSendCalled = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            // Call onSend callback
            if (opts && opts.onSend) {
                opts.onSend();
                onSendCalled = true;
            }
            // Then call onPlusTag to enable IDLE
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // Break IDLE via preCheck
            if (connection.preCheck) {
                await connection.preCheck();
            }
            return { next: () => {} };
        },
        write: () => {}
    });

    await idleCommand(connection);
    test.equal(onSendCalled, true);
    test.done();
};

module.exports['Commands: idle clears preCheck and queue on normal completion'] = async test => {
    let waitQueueResolved = false;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        exec: async (cmd, attrs, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // After onPlusTag, queue a preCheck but don't resolve yet
            if (connection.preCheck) {
                connection.preCheck().then(() => {
                    waitQueueResolved = true;
                });
            }
            // Return to complete IDLE - this should clear the queue
            return { next: () => {} };
        },
        write: () => {}
    });

    await idleCommand(connection);
    await new Promise(resolve => setImmediate(resolve));
    // preCheck should be cleared after completion
    test.equal(connection.preCheck, false);
    test.equal(waitQueueResolved, true);
    test.done();
};

module.exports['Commands: idle with maxIdleTime triggers preCheck after timeout'] = async test => {
    let preCheckCalled = false;
    let loopCount = 0;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        idling: false,
        exec: async (cmd, attrs, opts) => {
            loopCount++;
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // Simulate time passing - on first loop, wait for timer
            if (loopCount === 1) {
                // Wait a bit for the timer to fire
                await new Promise(resolve => setTimeout(resolve, 25));
            }
            // Check if preCheck was called by the timer
            if (connection.preCheck && loopCount === 1) {
                preCheckCalled = true;
                await connection.preCheck();
            }
            return { next: () => {} };
        },
        write: () => {}
    });

    // Use very short maxIdleTime
    await idleCommand(connection, 10);
    test.ok(preCheckCalled || loopCount > 1, 'preCheck should be called by timer or loop should restart');
    test.done();
};

module.exports['Commands: idle stillIdling triggers loop restart'] = async test => {
    let loopCount = 0;
    const connection = createMockConnection({
        state: 3,
        capabilities: new Map([['IDLE', true]]),
        idling: false,
        exec: async (cmd, attrs, opts) => {
            loopCount++;
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag();
            }
            // First iteration: let the timer set stillIdling and trigger preCheck
            if (loopCount === 1) {
                await new Promise(resolve => setTimeout(resolve, 20));
                // Timer should have called preCheck which sets stillIdling
            }
            // Second iteration: just complete
            if (connection.preCheck) {
                await connection.preCheck();
            }
            return { next: () => {} };
        },
        write: () => {}
    });

    await idleCommand(connection, 5);
    // Loop should have run at least once (could run twice if timer works)
    test.ok(loopCount >= 1, 'IDLE loop should have run');
    test.done();
};

// ============================================
// ID Command Tests
// ============================================

const idCommand = require('../lib/commands/id');

module.exports['Commands: id skips when no ID capability'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map() // No ID capability
    });

    const result = await idCommand(connection, { name: 'TestClient' });
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: id sends client info'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        }
    });

    await idCommand(connection, { name: 'TestClient', version: '1.0' });
    test.equal(execArgs.cmd, 'ID');
    test.ok(Array.isArray(execArgs.args));
    test.ok(execArgs.args[0].includes('name'));
    test.ok(execArgs.args[0].includes('TestClient'));
    test.done();
};

module.exports['Commands: id sends null when no clientInfo'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        }
    });

    await idCommand(connection, null);
    test.equal(execArgs.cmd, 'ID');
    test.equal(execArgs.args[0], null);
    test.done();
};

module.exports['Commands: id sends null for empty clientInfo'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        }
    });

    await idCommand(connection, {});
    test.equal(execArgs.cmd, 'ID');
    test.equal(execArgs.args[0], null);
    test.done();
};

module.exports['Commands: id parses server response'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ID) {
                await opts.untagged.ID({
                    attributes: [[{ value: 'name' }, { value: 'TestServer' }, { value: 'version' }, { value: '2.0' }, { value: 'vendor' }, { value: 'ACME' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await idCommand(connection, { name: 'TestClient' });
    test.equal(result.name, 'TestServer');
    test.equal(result.version, '2.0');
    test.equal(result.vendor, 'ACME');
    test.done();
};

module.exports['Commands: id updates serverInfo'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        serverInfo: {},
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ID) {
                await opts.untagged.ID({
                    attributes: [[{ value: 'name' }, { value: 'ImapServer' }, { value: 'support-url' }, { value: 'https://example.com' }]]
                });
            }
            return { next: () => {} };
        }
    });

    await idCommand(connection, { name: 'TestClient' });
    test.equal(connection.serverInfo.name, 'ImapServer');
    test.equal(connection.serverInfo['support-url'], 'https://example.com');
    test.done();
};

module.exports['Commands: id handles non-array server response'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ID) {
                // Some servers might send NIL or a single value
                await opts.untagged.ID({
                    attributes: [null]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await idCommand(connection, { name: 'TestClient' });
    test.ok(result);
    test.deepEqual(result, {});
    test.done();
};

module.exports['Commands: id formats date value'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        }
    });

    const testDate = new Date('2024-06-15T10:30:00Z');
    await idCommand(connection, { date: testDate });

    test.equal(execArgs.cmd, 'ID');
    // Date should be formatted, not passed as Date object
    test.ok(execArgs.args[0].includes('date'));
    test.done();
};

module.exports['Commands: id normalizes key names to lowercase'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ID) {
                await opts.untagged.ID({
                    attributes: [[{ value: 'NAME' }, { value: 'TestServer' }, { value: 'VERSION' }, { value: '1.0' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await idCommand(connection, { name: 'TestClient' });
    test.equal(result.name, 'TestServer');
    test.equal(result.version, '1.0');
    test.done();
};

module.exports['Commands: id trims key names'] = async test => {
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ID) {
                await opts.untagged.ID({
                    attributes: [[{ value: ' name ' }, { value: 'TestServer' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await idCommand(connection, { name: 'TestClient' });
    test.equal(result.name, 'TestServer');
    test.done();
};

module.exports['Commands: id handles error'] = async test => {
    let warnLogged = false;
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async () => {
            throw new Error('ID command failed');
        },
        log: {
            warn: () => {
                warnLogged = true;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await idCommand(connection, { name: 'TestClient' });
    test.equal(result, false);
    test.ok(warnLogged);
    test.done();
};

module.exports['Commands: id filters empty values'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        }
    });

    await idCommand(connection, { name: 'TestClient', empty: '', valid: 'value' });
    test.equal(execArgs.cmd, 'ID');
    // Empty values should be filtered out
    test.ok(execArgs.args[0].includes('name'));
    test.ok(execArgs.args[0].includes('valid'));
    test.done();
};

module.exports['Commands: id replaces whitespace in values'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        capabilities: new Map([['ID', true]]),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        }
    });

    await idCommand(connection, { name: 'Test\nClient\tApp' });
    test.equal(execArgs.cmd, 'ID');
    // Whitespace should be normalized to single spaces
    const nameIndex = execArgs.args[0].indexOf('name');
    test.ok(nameIndex >= 0);
    const nameValue = execArgs.args[0][nameIndex + 1];
    test.ok(!nameValue.includes('\n'));
    test.ok(!nameValue.includes('\t'));
    test.done();
};

// ============================================
// NAMESPACE Command Tests
// ============================================

const namespaceCommand = require('../lib/commands/namespace');

module.exports['Commands: namespace skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 }); // NOT_AUTHENTICATED

    const result = await namespaceCommand(connection);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: namespace with NAMESPACE capability'] = async test => {
    const connection = createMockConnection({
        state: 2, // AUTHENTICATED
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            test.equal(cmd, 'NAMESPACE');
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [
                        // personal namespaces
                        [[{ value: 'INBOX.' }, { value: '.' }]],
                        // other users
                        [[{ value: 'Users.' }, { value: '.' }]],
                        // shared
                        [[{ value: 'Shared.' }, { value: '.' }]]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    test.equal(result.prefix, 'INBOX.');
    test.equal(result.delimiter, '.');
    test.equal(connection.namespaces.personal[0].prefix, 'INBOX.');
    test.equal(connection.namespaces.other[0].prefix, 'Users.');
    test.equal(connection.namespaces.shared[0].prefix, 'Shared.');
    test.done();
};

module.exports['Commands: namespace fallback without capability'] = async test => {
    const connection = createMockConnection({
        state: 2, // AUTHENTICATED
        capabilities: new Map(), // No NAMESPACE capability
        exec: async (cmd, args, opts) => {
            test.equal(cmd, 'LIST');
            if (opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '/' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    test.equal(result.delimiter, '/');
    test.equal(connection.namespaces.other, false);
    test.equal(connection.namespaces.shared, false);
    test.done();
};

module.exports['Commands: namespace fallback adds delimiter to prefix'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [[{ value: '\\HasNoChildren' }], { value: '.' }, { value: 'INBOX' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    test.equal(result.delimiter, '.');
    test.done();
};

module.exports['Commands: namespace handles empty response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                // Provide minimal valid namespace even in "empty" case
                await opts.untagged.NAMESPACE({
                    attributes: [
                        [[{ value: '' }, { value: '.' }]], // minimal personal namespace
                        null,
                        null
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    test.equal(result.prefix, '');
    test.equal(result.delimiter, '.');
    test.done();
};

module.exports['Commands: namespace handles NIL namespaces'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [
                        [[{ value: '' }, { value: '/' }]], // personal
                        null, // other (NIL)
                        null // shared (NIL)
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    test.equal(result.delimiter, '/');
    test.equal(connection.namespaces.other, false);
    test.equal(connection.namespaces.shared, false);
    test.done();
};

module.exports['Commands: namespace handles NIL delimiter (RFC 2342)'] = async test => {
    // RFC 2342 §5: NIL delimiter means the namespace has no hierarchy.
    // The token parser emits a literal `null` for NIL.

    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [
                        [
                            [{ value: '' }, { value: '/' }],
                            [{ value: '#hidden' }, null]
                        ],
                        null,
                        null
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);

    // Guard against handler crash so a regression surfaces as a failed
    // assertion rather than fatal-halting the whole nodeunit suite.
    if (result && result.error) {
        test.ok(false, 'namespace command returned error sentinel — likely crashed on NIL delimiter');
        test.done();
        return;
    }
    if (!Array.isArray(connection.namespaces && connection.namespaces.personal)) {
        test.ok(false, 'connection.namespaces.personal is not an array (handler crashed mid-untagged-callback)');
        test.done();
        return;
    }

    test.equal(connection.namespaces.personal.length, 2, 'both personal entries should be parsed');

    test.equal(connection.namespaces.personal[0].prefix, '');
    test.equal(connection.namespaces.personal[0].delimiter, '/');

    // NIL-delimiter entry preserved with delimiter:null rather than dropped silently.
    test.equal(connection.namespaces.personal[1].prefix, '#hidden');
    test.equal(connection.namespaces.personal[1].delimiter, null);

    // Default namespace pointer resolves to the first valid personal entry.
    test.equal(connection.namespace.prefix, '');
    test.equal(connection.namespace.delimiter, '/');

    test.done();
};

module.exports['Commands: namespace handles NIL delimiter as only personal entry'] = async test => {
    // Edge case: only a NIL-delimiter entry in the personal section.
    // connection.namespace must still be set and usable downstream.

    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [[[{ value: '#hidden' }, null]], null, null]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);

    if (result && result.error) {
        test.ok(false, 'namespace command returned error sentinel — likely crashed on NIL delimiter');
        test.done();
        return;
    }
    if (!Array.isArray(connection.namespaces && connection.namespaces.personal)) {
        test.ok(false, 'connection.namespaces.personal is not an array (handler crashed mid-untagged-callback)');
        test.done();
        return;
    }

    test.equal(connection.namespaces.personal.length, 1);
    test.equal(connection.namespaces.personal[0].prefix, '#hidden');
    test.equal(connection.namespaces.personal[0].delimiter, null);

    test.ok(connection.namespace);
    test.equal(connection.namespace.prefix, '#hidden');
    test.equal(connection.namespace.delimiter, null);

    test.done();
};

module.exports['Commands: namespace handles NIL delimiter in other and shared sections'] = async test => {
    // NIL delimiter is also valid in the `other` and `shared` sections,
    // not just `personal`.

    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [[[{ value: '' }, { value: '/' }]], [[{ value: 'Other Users/' }, null]], [[{ value: 'Public/' }, null]]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);

    if (result && result.error) {
        test.ok(false, 'namespace command returned error sentinel — likely crashed on NIL delimiter');
        test.done();
        return;
    }

    test.ok(Array.isArray(connection.namespaces.other), 'other should be an array');
    test.equal(connection.namespaces.other.length, 1);
    test.equal(connection.namespaces.other[0].prefix, 'Other Users/');
    test.equal(connection.namespaces.other[0].delimiter, null);

    test.ok(Array.isArray(connection.namespaces.shared), 'shared should be an array');
    test.equal(connection.namespaces.shared.length, 1);
    test.equal(connection.namespaces.shared[0].prefix, 'Public/');
    test.equal(connection.namespaces.shared[0].delimiter, null);

    test.done();
};

module.exports['Commands: namespace skips malformed entries without crashing'] = async test => {
    // The filter must reject entries that don't match either the
    // (string-prefix, string-delimiter) or (string-prefix, NIL) shape,
    // so a single broken entry from a buggy server doesn't poison
    // the whole namespace list or crash the handler.

    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [
                        [
                            [{ value: '' }, { value: '/' }], // valid
                            [{ value: '#hidden' }, null], // valid (NIL delimiter)
                            [{ value: 'broken' }], // too short — rejected
                            [null, { value: '/' }], // null prefix — rejected
                            [{ value: 123 }, { value: '/' }] // non-string prefix — rejected
                        ],
                        null,
                        null
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);

    if (result && result.error) {
        test.ok(false, 'namespace command returned error sentinel — likely crashed on malformed entry');
        test.done();
        return;
    }

    test.equal(connection.namespaces.personal.length, 2, 'only the two well-formed entries should be kept');
    test.equal(connection.namespaces.personal[0].prefix, '');
    test.equal(connection.namespaces.personal[1].prefix, '#hidden');
    test.equal(connection.namespaces.personal[1].delimiter, null);

    test.done();
};

module.exports['Commands: namespace handles multiple personal namespaces'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [
                        [
                            [{ value: 'INBOX' }, { value: '.' }],
                            [{ value: 'Mail' }, { value: '/' }]
                        ],
                        null,
                        null
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    test.equal(connection.namespaces.personal.length, 2);
    test.equal(connection.namespaces.personal[0].prefix, 'INBOX.');
    test.equal(connection.namespaces.personal[1].prefix, 'Mail/');
    test.done();
};

module.exports['Commands: namespace works in SELECTED state'] = async test => {
    const connection = createMockConnection({
        state: 3, // SELECTED
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [[[{ value: '' }, { value: '/' }]], null, null]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    test.equal(result.delimiter, '/');
    test.done();
};

module.exports['Commands: namespace handles error'] = async test => {
    let warnLogged = false;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async () => {
            const err = new Error('Namespace failed');
            err.responseStatus = 'NO';
            err.responseText = 'Command not supported';
            throw err;
        },
        log: {
            warn: () => {
                warnLogged = true;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result.error);
    test.equal(result.status, 'NO');
    test.equal(result.text, 'Command not supported');
    test.ok(warnLogged);
    test.done();
};

module.exports['Commands: namespace fallback handles LIST error'] = async test => {
    let warnLogged = false;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map(), // No NAMESPACE capability
        exec: async () => {
            throw new Error('LIST failed');
        },
        log: {
            warn: () => {
                warnLogged = true;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    // Should return default namespace even on error
    test.equal(result.prefix, '');
    test.ok(warnLogged);
    test.done();
};

module.exports['Commands: namespace appends delimiter to prefix if missing'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.NAMESPACE) {
                await opts.untagged.NAMESPACE({
                    attributes: [
                        // prefix without trailing delimiter
                        [[{ value: 'INBOX' }, { value: '.' }]],
                        null,
                        null
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.equal(result.prefix, 'INBOX.');
    test.done();
};

module.exports['Commands: namespace fallback strips leading delimiter from prefix'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.LIST) {
                await opts.untagged.LIST({
                    attributes: [
                        [{ value: '\\HasNoChildren' }],
                        { value: '/' },
                        { value: '/INBOX' } // Leading delimiter
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.equal(result.prefix, 'INBOX/');
    test.done();
};

module.exports['Commands: namespace ignores empty NAMESPACE response attributes'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (cmd === 'NAMESPACE' && opts && opts.untagged && opts.untagged.NAMESPACE) {
                // Empty attributes - the callback should return early
                await opts.untagged.NAMESPACE({
                    attributes: []
                });
                // Also provide a valid NAMESPACE to avoid error
                await opts.untagged.NAMESPACE({
                    attributes: [[[{ value: 'INBOX.' }, { value: '.' }]], null, null]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    // Should return namespace from the second call
    test.equal(result.prefix, 'INBOX.');
    test.equal(result.delimiter, '.');
    test.done();
};

module.exports['Commands: namespace sets default when personal namespace is empty array'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['NAMESPACE', true]]),
        exec: async (cmd, args, opts) => {
            if (cmd === 'NAMESPACE' && opts && opts.untagged && opts.untagged.NAMESPACE) {
                // Provide an array where entries don't pass the filter
                // (entry.length < 2), so getNamsepaceInfo returns []
                await opts.untagged.NAMESPACE({
                    attributes: [
                        [[]], // array with one empty entry - filter removes it, returns []
                        null, // other
                        null // shared
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    // Should set default personal namespace when personal[0] is falsy
    test.equal(result.prefix, '');
    test.equal(result.delimiter, '.');
    test.done();
};

module.exports['Commands: namespace fallback ignores empty LIST attributes'] = async test => {
    let listCallCount = 0;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map(), // No NAMESPACE capability
        exec: async (cmd, args, opts) => {
            if (cmd === 'LIST' && opts && opts.untagged && opts.untagged.LIST) {
                listCallCount++;
                // Empty attributes - the callback should return early
                await opts.untagged.LIST({
                    attributes: []
                });
            }
            return { next: () => {} };
        }
    });

    const result = await namespaceCommand(connection);
    test.ok(result);
    test.equal(listCallCount, 1);
    // With empty LIST, prefix and delimiter are undefined
    test.equal(result.prefix, '');
    test.done();
};

// ============================================
// QUOTA Command Tests
// ============================================

const quotaCommand = require('../lib/commands/quota');

module.exports['Commands: quota skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 }); // NOT_AUTHENTICATED

    const result = await quotaCommand(connection, 'INBOX');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: quota skips when no path'] = async test => {
    const connection = createMockConnection({ state: 2 });

    const result = await quotaCommand(connection, null);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: quota returns false without capability'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map() // No QUOTA capability
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.equal(result, false);
    test.done();
};

module.exports['Commands: quota with storage quota'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            test.equal(cmd, 'GETQUOTAROOT');
            if (opts && opts.untagged) {
                if (opts.untagged.QUOTAROOT) {
                    await opts.untagged.QUOTAROOT({
                        attributes: [
                            { value: 'INBOX' },
                            { value: 'user.root' } // quota root
                        ]
                    });
                }
                if (opts.untagged.QUOTA) {
                    await opts.untagged.QUOTA({
                        attributes: [
                            { value: 'user.root' },
                            [
                                { value: 'STORAGE' },
                                { value: '500' }, // 500 KB used
                                { value: '1000' } // 1000 KB limit
                            ]
                        ]
                    });
                }
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result);
    test.equal(result.path, 'INBOX');
    test.equal(result.quotaRoot, 'user.root');
    test.equal(result.storage.usage, 500 * 1024); // Converted to bytes
    test.equal(result.storage.limit, 1000 * 1024);
    test.equal(result.storage.status, '50%');
    test.done();
};

module.exports['Commands: quota with message quota'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                await opts.untagged.QUOTA({
                    attributes: [{ value: 'root' }, [{ value: 'MESSAGE' }, { value: '100' }, { value: '1000' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result);
    // MESSAGE quota is not multiplied by 1024
    test.equal(result.message.usage, 100);
    test.equal(result.message.limit, 1000);
    test.equal(result.message.status, '10%');
    test.done();
};

module.exports['Commands: quota with multiple quota types'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                await opts.untagged.QUOTA({
                    attributes: [
                        { value: '' },
                        [{ value: 'STORAGE' }, { value: '250' }, { value: '500' }, { value: 'MESSAGE' }, { value: '50' }, { value: '100' }]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result.storage);
    test.ok(result.message);
    test.equal(result.storage.usage, 250 * 1024);
    test.equal(result.message.usage, 50);
    test.done();
};

module.exports['Commands: quota fetches GETQUOTA when quotaRoot but no QUOTA response'] = async test => {
    let getQuotaCalled = false;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (cmd === 'GETQUOTAROOT') {
                if (opts && opts.untagged && opts.untagged.QUOTAROOT) {
                    await opts.untagged.QUOTAROOT({
                        attributes: [{ value: 'INBOX' }, { value: 'user.root' }]
                    });
                }
                // No QUOTA response
            } else if (cmd === 'GETQUOTA') {
                getQuotaCalled = true;
                test.deepEqual(args, [{ type: 'ATOM', value: 'user.root' }]);
                if (opts && opts.untagged && opts.untagged.QUOTA) {
                    await opts.untagged.QUOTA({
                        attributes: [{ value: 'user.root' }, [{ value: 'STORAGE' }, { value: '100' }, { value: '200' }]]
                    });
                }
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(getQuotaCalled);
    test.equal(result.quotaRoot, 'user.root');
    test.equal(result.storage.usage, 100 * 1024);
    test.done();
};

module.exports['Commands: quota handles zero limit'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                await opts.untagged.QUOTA({
                    attributes: [
                        { value: '' },
                        [
                            { value: 'STORAGE' },
                            { value: '0' },
                            { value: '0' } // Zero limit
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result.storage);
    test.equal(result.storage.usage, 0);
    test.equal(result.storage.limit, 0);
    // No status when limit is 0
    test.equal(result.storage.status, undefined);
    test.done();
};

module.exports['Commands: quota handles empty attributes'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                await opts.untagged.QUOTA({
                    attributes: [
                        { value: '' },
                        [] // Empty quota list
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result);
    test.equal(result.path, 'INBOX');
    test.equal(result.storage, undefined);
    test.done();
};

module.exports['Commands: quota works in SELECTED state'] = async test => {
    const connection = createMockConnection({
        state: 3, // SELECTED
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                await opts.untagged.QUOTA({
                    attributes: [{ value: '' }, [{ value: 'STORAGE' }, { value: '10' }, { value: '100' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result);
    test.equal(result.storage.status, '10%');
    test.done();
};

module.exports['Commands: quota handles error'] = async test => {
    let warnLogged = false;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async () => {
            const err = new Error('Quota failed');
            err.response = { attributes: [] };
            throw err;
        },
        log: {
            warn: () => {
                warnLogged = true;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.equal(result, false);
    test.ok(warnLogged);
    test.done();
};

module.exports['Commands: quota handles error with status code'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async () => {
            const err = new Error('Quota failed');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'ATOM',
                        value: '',
                        section: [{ type: 'ATOM', value: 'NOQUOTA' }]
                    }
                ]
            };
            throw err;
        },
        log: {
            warn: () => {},
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.equal(result, false);
    test.done();
};

module.exports['Commands: quota normalizes path'] = async test => {
    let capturedArgs = null;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        namespace: { delimiter: '/', prefix: 'INBOX/' },
        exec: async (cmd, args) => {
            capturedArgs = args;
            return { next: () => {} };
        }
    });

    await quotaCommand(connection, 'Subfolder');
    test.ok(capturedArgs);
    test.done();
};

module.exports['Commands: quota handles non-numeric values'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                await opts.untagged.QUOTA({
                    attributes: [
                        { value: '' },
                        [
                            { value: 'STORAGE' },
                            { value: 'invalid' }, // Non-numeric usage
                            { value: 'also-invalid' } // Non-numeric limit
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result);
    // Non-numeric values should be skipped - no storage data set
    test.equal(result.storage, undefined);
    test.done();
};

module.exports['Commands: quota calculates percentage correctly'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                await opts.untagged.QUOTA({
                    attributes: [{ value: '' }, [{ value: 'MESSAGE' }, { value: '333' }, { value: '1000' }]]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.equal(result.message.status, '33%'); // Rounded
    test.done();
};

module.exports['Commands: quota handles falsy key in attributes'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                // First attribute (i=0) has invalid key (null value), so key becomes false
                // Then i=1 and i=2 should be skipped due to !key check
                await opts.untagged.QUOTA({
                    attributes: [
                        { value: '' },
                        [
                            { value: null }, // Invalid key at i=0 -> key = false
                            { value: '100' }, // i=1, skipped because !key
                            { value: '1000' } // i=2, skipped because !key
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result);
    // No quota data should be set since key was falsy
    test.equal(Object.keys(result).filter(k => k !== 'path').length, 0);
    test.done();
};

module.exports['Commands: quota sets limit without prior usage'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['QUOTA', true]]),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.QUOTA) {
                // Provide only the limit (i=2) without usage (i=1) being valid
                await opts.untagged.QUOTA({
                    attributes: [
                        { value: '' },
                        [
                            { value: 'STORAGE' }, // i=0, key = 'storage'
                            { value: 'invalid' }, // i=1, usage - invalid number, skipped
                            { value: '1000' } // i=2, limit - should create map[key] first
                        ]
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await quotaCommand(connection, 'INBOX');
    test.ok(result);
    test.ok(result.storage);
    test.equal(result.storage.limit, 1024000); // 1000 * 1024 for storage
    test.equal(result.storage.usage, undefined);
    test.done();
};

// ============================================
// AUTHENTICATE Command Tests
// ============================================

const authenticateCommand = require('../lib/commands/authenticate');

module.exports['Commands: authenticate skips when already authenticated'] = async test => {
    const connection = createMockConnection({
        state: 2 // AUTHENTICATED
    });

    const result = await authenticateCommand(connection, 'user', { password: 'pass' });
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: authenticate with OAUTHBEARER'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 1, // NOT_AUTHENTICATED
        capabilities: new Map([['AUTH=OAUTHBEARER', true]]),
        servername: 'imap.example.com',
        authCapabilities: new Map(),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        },
        write: () => {}
    });

    const result = await authenticateCommand(connection, 'user@example.com', { accessToken: 'token123' });
    test.equal(result, 'user@example.com');
    test.equal(execArgs.cmd, 'AUTHENTICATE');
    test.equal(execArgs.args[0].value, 'OAUTHBEARER');
    test.ok(connection.authCapabilities.has('AUTH=OAUTHBEARER'));
    test.done();
};

module.exports['Commands: authenticate with XOAUTH2'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=XOAUTH2', true]]),
        servername: 'imap.example.com',
        authCapabilities: new Map(),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        },
        write: () => {}
    });

    const result = await authenticateCommand(connection, 'user@example.com', { accessToken: 'token123' });
    test.equal(result, 'user@example.com');
    test.equal(execArgs.args[0].value, 'XOAUTH2');
    test.ok(connection.authCapabilities.has('AUTH=XOAUTH2'));
    test.done();
};

module.exports['Commands: authenticate with XOAUTH (legacy)'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=XOAUTH', true]]),
        servername: 'imap.example.com',
        authCapabilities: new Map(),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        },
        write: () => {}
    });

    const result = await authenticateCommand(connection, 'user@example.com', { accessToken: 'token123' });
    test.equal(result, 'user@example.com');
    test.equal(execArgs.args[0].value, 'XOAUTH2');
    test.done();
};

module.exports['Commands: authenticate OAuth handles error response'] = async test => {
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=OAUTHBEARER', true]]),
        servername: 'imap.example.com',
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            // Simulate server sending error in plus tag
            if (opts && opts.onPlusTag) {
                const errorJson = Buffer.from(JSON.stringify({ status: '401', error: 'invalid_token' })).toString('base64');
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: errorJson }]
                });
            }
            const err = new Error('Authentication failed');
            err.response = { attributes: [] };
            throw err;
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    try {
        await authenticateCommand(connection, 'user@example.com', { accessToken: 'bad_token' });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.authenticationFailed);
        test.ok(err.oauthError);
        test.equal(err.oauthError.status, '401');
    }
    test.done();
};

module.exports['Commands: authenticate OAuth handles malformed error response'] = async test => {
    let debugLogged = false;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=OAUTHBEARER', true]]),
        servername: 'imap.example.com',
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.onPlusTag) {
                // Malformed base64/JSON
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: 'not-valid-base64!' }]
                });
            }
            const err = new Error('Authentication failed');
            err.response = { attributes: [] };
            throw err;
        },
        write: () => {},
        log: {
            debug: () => {
                debugLogged = true;
            },
            warn: () => {},
            trace: () => {}
        }
    });

    try {
        await authenticateCommand(connection, 'user@example.com', { accessToken: 'token' });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.authenticationFailed);
        test.ok(debugLogged); // Should log the parse error
        test.equal(err.oauthError, undefined); // No oauthError since parse failed
    }
    test.done();
};

module.exports['Commands: authenticate OAuth error with serverResponseCode'] = async test => {
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=OAUTHBEARER', true]]),
        servername: 'imap.example.com',
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag({});
            }
            const err = new Error('Authentication failed');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'AUTHORIZATIONFAILED' }]
                    },
                    { type: 'TEXT', value: 'OAuth token expired' }
                ]
            };
            throw err;
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    try {
        await authenticateCommand(connection, 'user@example.com', { accessToken: 'expired_token' });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.authenticationFailed);
        test.equal(err.serverResponseCode, 'AUTHORIZATIONFAILED');
    }
    test.done();
};

module.exports['Commands: authenticate with PLAIN'] = async test => {
    let execArgs = null;
    let writtenData = null;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=PLAIN', true]]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag({});
            }
            return { next: () => {} };
        },
        write: data => {
            writtenData = data;
        },
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    const result = await authenticateCommand(connection, 'testuser', { password: 'testpass' });
    test.equal(result, 'testuser');
    test.equal(execArgs.cmd, 'AUTHENTICATE');
    test.equal(execArgs.args[0].value, 'PLAIN');
    // Verify PLAIN format: \x00username\x00password
    const decoded = Buffer.from(writtenData, 'base64').toString();
    test.equal(decoded, '\x00testuser\x00testpass');
    test.ok(connection.authCapabilities.has('AUTH=PLAIN'));
    test.done();
};

module.exports['Commands: authenticate with PLAIN and authzid'] = async test => {
    let writtenData = null;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=PLAIN', true]]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag({});
            }
            return { next: () => {} };
        },
        write: data => {
            writtenData = data;
        },
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    const result = await authenticateCommand(connection, 'admin', {
        password: 'adminpass',
        authzid: 'impersonated_user'
    });
    test.equal(result, 'impersonated_user'); // Returns authzid when provided
    // Verify PLAIN format with authzid: authzid\x00username\x00password
    const decoded = Buffer.from(writtenData, 'base64').toString();
    test.equal(decoded, 'impersonated_user\x00admin\x00adminpass');
    test.done();
};

module.exports['Commands: authenticate with PLAIN forced via loginMethod'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([
            ['AUTH=LOGIN', true],
            ['AUTH=PLAIN', true]
        ]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag({});
            }
            return { next: () => {} };
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    await authenticateCommand(connection, 'user', { password: 'pass', loginMethod: 'AUTH=PLAIN' });
    test.equal(execArgs.args[0].value, 'PLAIN');
    test.done();
};

module.exports['Commands: authenticate with LOGIN'] = async test => {
    let execArgs = null;
    let writeCount = 0;
    let writtenValues = [];
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=LOGIN', true]]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.onPlusTag) {
                // Simulate server prompts
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: Buffer.from('Username:').toString('base64') }]
                });
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: Buffer.from('Password:').toString('base64') }]
                });
            }
            return { next: () => {} };
        },
        write: data => {
            writeCount++;
            writtenValues.push(Buffer.from(data, 'base64').toString());
        },
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    const result = await authenticateCommand(connection, 'loginuser', { password: 'loginpass' });
    test.equal(result, 'loginuser');
    test.equal(execArgs.args[0].value, 'LOGIN');
    test.equal(writeCount, 2);
    test.equal(writtenValues[0], 'loginuser');
    test.equal(writtenValues[1], 'loginpass');
    test.ok(connection.authCapabilities.has('AUTH=LOGIN'));
    test.done();
};

module.exports['Commands: authenticate with LOGIN handles user name prompt'] = async test => {
    let writtenValues = [];
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=LOGIN', true]]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.onPlusTag) {
                // Some servers use "User Name" instead of "Username"
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: Buffer.from('User Name:').toString('base64') }]
                });
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: Buffer.from('Password').toString('base64') }]
                });
            }
            return { next: () => {} };
        },
        write: data => {
            writtenValues.push(Buffer.from(data, 'base64').toString());
        },
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    await authenticateCommand(connection, 'testuser', { password: 'testpass' });
    test.equal(writtenValues[0], 'testuser');
    test.equal(writtenValues[1], 'testpass');
    test.done();
};

module.exports['Commands: authenticate with LOGIN throws on unknown question'] = async test => {
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=LOGIN', true]]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: Buffer.from('Unknown Question:').toString('base64') }]
                });
            }
            return { next: () => {} };
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    try {
        await authenticateCommand(connection, 'user', { password: 'pass' });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.message.includes('Unknown LOGIN question'));
    }
    test.done();
};

module.exports['Commands: authenticate with LOGIN forced via loginMethod'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([
            ['AUTH=PLAIN', true],
            ['AUTH=LOGIN', true]
        ]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: Buffer.from('Username:').toString('base64') }]
                });
                await opts.onPlusTag({
                    attributes: [{ type: 'TEXT', value: Buffer.from('Password:').toString('base64') }]
                });
            }
            return { next: () => {} };
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    await authenticateCommand(connection, 'user', { password: 'pass', loginMethod: 'AUTH=LOGIN' });
    test.equal(execArgs.args[0].value, 'LOGIN');
    test.done();
};

module.exports['Commands: authenticate PLAIN handles error'] = async test => {
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=PLAIN', true]]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag({});
            }
            const err = new Error('Authentication failed');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'ATOM',
                        value: '',
                        section: [{ type: 'ATOM', value: 'AUTHENTICATIONFAILED' }]
                    }
                ]
            };
            throw err;
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    try {
        await authenticateCommand(connection, 'user', { password: 'wrongpass' });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.authenticationFailed);
        test.equal(err.serverResponseCode, 'AUTHENTICATIONFAILED');
    }
    test.done();
};

module.exports['Commands: authenticate LOGIN handles error'] = async test => {
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=LOGIN', true]]),
        authCapabilities: new Map(),
        exec: async () => {
            const err = new Error('Login failed');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'SECTION',
                        section: [{ type: 'ATOM', value: 'AUTHENTICATIONFAILED' }]
                    },
                    { type: 'TEXT', value: 'Invalid credentials' }
                ]
            };
            throw err;
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    try {
        await authenticateCommand(connection, 'user', { password: 'pass' });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.authenticationFailed);
        test.equal(err.serverResponseCode, 'AUTHENTICATIONFAILED');
    }
    test.done();
};

module.exports['Commands: authenticate throws unsupported mechanism'] = async test => {
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map() // No auth capabilities
    });

    try {
        await authenticateCommand(connection, 'user', { password: 'pass' });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.message.includes('Unsupported authentication mechanism'));
    }
    test.done();
};

module.exports['Commands: authenticate throws unsupported for accessToken without OAuth capability'] = async test => {
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([['AUTH=PLAIN', true]]) // No OAuth capability
    });

    try {
        await authenticateCommand(connection, 'user', { accessToken: 'token123' });
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.ok(err.message.includes('Unsupported authentication mechanism'));
    }
    test.done();
};

module.exports['Commands: authenticate prefers PLAIN over LOGIN by default'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([
            ['AUTH=LOGIN', true],
            ['AUTH=PLAIN', true]
        ]),
        authCapabilities: new Map(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.onPlusTag) {
                await opts.onPlusTag({});
            }
            return { next: () => {} };
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    await authenticateCommand(connection, 'user', { password: 'pass' });
    test.equal(execArgs.args[0].value, 'PLAIN'); // PLAIN should be preferred
    test.done();
};

module.exports['Commands: authenticate prefers OAuth when accessToken provided'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 1,
        capabilities: new Map([
            ['AUTH=PLAIN', true],
            ['AUTH=OAUTHBEARER', true]
        ]),
        servername: 'imap.example.com',
        authCapabilities: new Map(),
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return { next: () => {} };
        },
        write: () => {},
        log: {
            debug: () => {},
            warn: () => {},
            trace: () => {}
        }
    });

    await authenticateCommand(connection, 'user', { accessToken: 'token', password: 'pass' });
    test.equal(execArgs.args[0].value, 'OAUTHBEARER'); // OAuth preferred when token provided
    test.done();
};

// ============================================
// CREATE Command Tests
// ============================================

module.exports['Commands: create skips when not authenticated'] = async test => {
    const connection = createMockConnection({ state: 1 }); // NOT_AUTHENTICATED

    const result = await createCommand(connection, 'NewFolder');
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: create mailbox success'] = async test => {
    let execArgs = null;
    let subscribeCalled = false;
    const connection = createMockConnection({
        state: 2, // AUTHENTICATED
        exec: async (cmd, args) => {
            execArgs = { cmd, args };
            return {
                next: () => {},
                response: { attributes: [] }
            };
        },
        run: async (cmd, path) => {
            if (cmd === 'SUBSCRIBE') {
                subscribeCalled = true;
                test.equal(path, 'NewFolder');
            }
        }
    });

    const result = await createCommand(connection, 'NewFolder');
    test.ok(result);
    test.equal(result.path, 'NewFolder');
    test.equal(result.created, true);
    test.equal(execArgs.cmd, 'CREATE');
    test.ok(subscribeCalled);
    test.done();
};

module.exports['Commands: create works in SELECTED state'] = async test => {
    const connection = createMockConnection({
        state: 3, // SELECTED
        exec: async () => ({
            next: () => {},
            response: { attributes: [] }
        }),
        run: async () => {}
    });

    const result = await createCommand(connection, 'NewFolder');
    test.ok(result);
    test.equal(result.created, true);
    test.done();
};

module.exports['Commands: create with MAILBOXID response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [{ value: 'MAILBOXID' }, [{ value: 'F12345' }]]
                    }
                ]
            }
        }),
        run: async () => {}
    });

    const result = await createCommand(connection, 'NewFolder');
    test.ok(result);
    test.equal(result.mailboxId, 'F12345');
    test.equal(result.created, true);
    test.done();
};

module.exports['Commands: create normalizes path'] = async test => {
    let capturedArgs = null;
    const connection = createMockConnection({
        state: 2,
        namespace: { delimiter: '/', prefix: 'INBOX/' },
        exec: async (cmd, args) => {
            capturedArgs = args;
            return {
                next: () => {},
                response: { attributes: [] }
            };
        },
        run: async () => {}
    });

    await createCommand(connection, 'Subfolder');
    test.ok(capturedArgs);
    test.done();
};

module.exports['Commands: create handles ALREADYEXISTS'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Mailbox already exists');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'ATOM',
                        value: '',
                        section: [{ type: 'ATOM', value: 'ALREADYEXISTS' }]
                    }
                ]
            };
            throw err;
        },
        run: async () => {},
        log: {
            warn: () => {},
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await createCommand(connection, 'ExistingFolder');
    test.ok(result);
    test.equal(result.path, 'ExistingFolder');
    test.equal(result.created, false);
    test.done();
};

module.exports['Commands: create throws on other errors'] = async test => {
    let warnLogged = false;
    const connection = createMockConnection({
        state: 2,
        exec: async () => {
            const err = new Error('Permission denied');
            err.response = {
                tag: 'A1',
                command: 'NO',
                attributes: [
                    {
                        type: 'ATOM',
                        value: '',
                        section: [{ type: 'ATOM', value: 'NOPERM' }]
                    }
                ]
            };
            throw err;
        },
        run: async () => {},
        log: {
            warn: () => {
                warnLogged = true;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    try {
        await createCommand(connection, 'RestrictedFolder');
        test.ok(false, 'Should have thrown');
    } catch (err) {
        test.equal(err.serverResponseCode, 'NOPERM');
        test.ok(warnLogged);
    }
    test.done();
};

module.exports['Commands: create handles empty section'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [] // Empty section
                    }
                ]
            }
        }),
        run: async () => {}
    });

    const result = await createCommand(connection, 'NewFolder');
    test.ok(result);
    test.equal(result.created, true);
    test.equal(result.mailboxId, undefined);
    test.done();
};

module.exports['Commands: create handles invalid MAILBOXID format'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [
                            { value: 'MAILBOXID' },
                            { value: 'not-an-array' } // Should be array
                        ]
                    }
                ]
            }
        }),
        run: async () => {}
    });

    const result = await createCommand(connection, 'NewFolder');
    test.ok(result);
    test.equal(result.created, true);
    // mailboxId should not be set due to invalid format
    test.equal(result.mailboxId, undefined);
    test.done();
};

module.exports['Commands: create handles null key in section'] = async test => {
    const connection = createMockConnection({
        state: 2,
        exec: async () => ({
            next: () => {},
            response: {
                attributes: [
                    {
                        section: [
                            null, // null key
                            [{ value: 'F12345' }]
                        ]
                    }
                ]
            }
        }),
        run: async () => {}
    });

    const result = await createCommand(connection, 'NewFolder');
    test.ok(result);
    test.equal(result.created, true);
    test.done();
};

// ============================================
// ENABLE Command Tests
// ============================================

module.exports['Commands: enable skips without ENABLE capability'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map() // No ENABLE capability
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: enable skips when not authenticated'] = async test => {
    const connection = createMockConnection({
        state: 3, // SELECTED - not AUTHENTICATED
        capabilities: new Map([['ENABLE', true]])
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: enable skips when no supported extensions'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([['ENABLE', true]]) // Has ENABLE but not CONDSTORE
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.equal(result, undefined);
    test.done();
};

module.exports['Commands: enable single extension'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        enabled: new Set(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: [{ value: 'CONDSTORE' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.ok(result instanceof Set);
    test.ok(result.has('CONDSTORE'));
    test.equal(execArgs.cmd, 'ENABLE');
    test.equal(execArgs.args[0].value, 'CONDSTORE');
    test.ok(connection.enabled.has('CONDSTORE'));
    test.done();
};

module.exports['Commands: enable multiple extensions'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true],
            ['QRESYNC', true]
        ]),
        enabled: new Set(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: [{ value: 'CONDSTORE' }, { value: 'QRESYNC' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE', 'QRESYNC']);
    test.ok(result instanceof Set);
    test.ok(result.has('CONDSTORE'));
    test.ok(result.has('QRESYNC'));
    test.equal(execArgs.args.length, 2);
    test.done();
};

module.exports['Commands: enable filters unsupported extensions'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
            // QRESYNC not supported
        ]),
        enabled: new Set(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: [{ value: 'CONDSTORE' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE', 'QRESYNC']);
    test.ok(result instanceof Set);
    test.ok(result.has('CONDSTORE'));
    test.ok(!result.has('QRESYNC'));
    // Only CONDSTORE should be in the request
    test.equal(execArgs.args.length, 1);
    test.equal(execArgs.args[0].value, 'CONDSTORE');
    test.done();
};

module.exports['Commands: enable converts to uppercase'] = async test => {
    let execArgs = null;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        enabled: new Set(),
        exec: async (cmd, args, opts) => {
            execArgs = { cmd, args };
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: [{ value: 'condstore' }]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await enableCommand(connection, ['condstore']); // lowercase
    test.ok(result instanceof Set);
    test.ok(result.has('CONDSTORE')); // Stored as uppercase
    test.equal(execArgs.args[0].value, 'CONDSTORE'); // Sent as uppercase
    test.done();
};

module.exports['Commands: enable handles empty ENABLED response'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        enabled: new Set(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: [] // Empty
                });
            }
            return { next: () => {} };
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.ok(result instanceof Set);
    test.equal(result.size, 0);
    test.done();
};

module.exports['Commands: enable handles null attributes'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        enabled: new Set(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: null
                });
            }
            return { next: () => {} };
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.ok(result instanceof Set);
    test.equal(result.size, 0);
    test.done();
};

module.exports['Commands: enable trims response values'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        enabled: new Set(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: [{ value: '  CONDSTORE  ' }] // With whitespace
                });
            }
            return { next: () => {} };
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.ok(result.has('CONDSTORE'));
    test.done();
};

module.exports['Commands: enable handles error'] = async test => {
    let warnLogged = false;
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        enabled: new Set(),
        exec: async () => {
            throw new Error('Enable failed');
        },
        log: {
            warn: () => {
                warnLogged = true;
            },
            debug: () => {},
            trace: () => {}
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.equal(result, false);
    test.ok(warnLogged);
    test.done();
};

module.exports['Commands: enable skips non-string attribute values'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true]
        ]),
        enabled: new Set(),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: [
                        { value: 'CONDSTORE' },
                        { value: null }, // null value
                        { value: 123 }, // number value
                        { notValue: 'test' } // missing value property
                    ]
                });
            }
            return { next: () => {} };
        }
    });

    const result = await enableCommand(connection, ['CONDSTORE']);
    test.ok(result instanceof Set);
    test.equal(result.size, 1);
    test.ok(result.has('CONDSTORE'));
    test.done();
};

module.exports['Commands: enable updates connection.enabled'] = async test => {
    const connection = createMockConnection({
        state: 2,
        capabilities: new Map([
            ['ENABLE', true],
            ['CONDSTORE', true],
            ['UTF8=ACCEPT', true]
        ]),
        enabled: new Set(['EXISTING']),
        exec: async (cmd, args, opts) => {
            if (opts && opts.untagged && opts.untagged.ENABLED) {
                await opts.untagged.ENABLED({
                    attributes: [{ value: 'CONDSTORE' }, { value: 'UTF8=ACCEPT' }]
                });
            }
            return { next: () => {} };
        }
    });

    await enableCommand(connection, ['CONDSTORE', 'UTF8=ACCEPT']);
    // connection.enabled should be replaced with new set
    test.ok(connection.enabled.has('CONDSTORE'));
    test.ok(connection.enabled.has('UTF8=ACCEPT'));
    test.ok(!connection.enabled.has('EXISTING')); // Old value should be gone
    test.done();
};

// ============================================
// Download / DownloadMany Tests
// ============================================

const { ImapFlow } = require('../lib/imap-flow');

module.exports['Commands: download returns empty when no mailbox selected'] = async test => {
    let client = new ImapFlow({
        host: 'imap.example.com',
        port: 993,
        auth: { user: 'test', pass: 'test' }
    });
    // mailbox is not set by default
    let result = await client.download('1', '1.2');
    test.deepEqual(result, {});
    test.done();
};

module.exports['Commands: downloadMany returns empty when no mailbox selected'] = async test => {
    let client = new ImapFlow({
        host: 'imap.example.com',
        port: 993,
        auth: { user: 'test', pass: 'test' }
    });
    let result = await client.downloadMany('1', ['2', '3']);
    test.deepEqual(result, {});
    test.done();
};

module.exports['Commands: download with fetchOne returning null'] = async test => {
    let client = new ImapFlow({
        host: 'imap.example.com',
        port: 993,
        auth: { user: 'test', pass: 'test' }
    });
    // Set mailbox so download doesn't return {} early
    client.mailbox = { path: 'INBOX' };
    // Mock fetchOne to return null (message not found)
    client.fetchOne = async () => null;

    // part '1' triggers the bodyStructure check path
    let result = await client.download('1', '1');
    test.equal(result.response, false);
    test.equal(result.chunk, false);
    test.done();
};

module.exports['Commands: downloadMany with fetchOne returning null'] = async test => {
    let client = new ImapFlow({
        host: 'imap.example.com',
        port: 993,
        auth: { user: 'test', pass: 'test' }
    });
    client.mailbox = { path: 'INBOX' };
    client.fetchOne = async () => null;

    let result = await client.downloadMany('1', ['2', '3']);
    test.equal(result.response, false);
    test.done();
};
