import { Option } from 'commander';
import { PrettyPrint } from '../output/pretty_print.js';

const BASE = '/api/rainbow/massprovisioning/v1.0';

export class MassPro {
    constructor(program, logger, services) {
        this.logger = logger;
        this.services = services;
        services['masspro'] = this;

        this.logger.debug('MassPro.constructor');

        const masspro = program
            .command('masspro')
            .description('Mass provisioning users, directories, devices...');

        // ── USERS ────────────────────────────────────────────────────────────

        masspro
            .command('template')
            .argument('[filename]', 'output filename', 'template.csv')
            .description('Download CSV template for mass provisioning')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('-t, --type <type>', 'import type: user, device, useranddevice, rainbowvoice').default('user'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const companyId = options.company || await this._getMyCompanyId();
                        const params = [['mode', options.type]];
                        if (companyId) params.push(['companyId', companyId]);
                        return await this._downloadCSV(`${BASE}/users/template`, params, filename);
                    },
                    (msg) => { console.log(msg); }
                );
            });

        masspro
            .command('check')
            .argument('<filename>', 'CSV file to check')
            .description('Check a CSV file before importing')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('-t, --type <type>', 'import type: user, device, useranddevice, rainbowvoice').default('user'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this._checkCSV(filename, options); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('import')
            .argument('<filename>', 'CSV file to import')
            .description('Import users from a CSV file')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('-t, --type <type>', 'import type: user, device, useranddevice, rainbowvoice').default('user'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('--noemails', 'disable notification emails'))
            .addOption(new Option('--nostrict', 'allow non-strict mode (enables creates/deletes)'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this._importCSV(filename, options); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('imports')
            .description('List user import jobs')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = await this._baseParamsWithFallback(options);
                        return await this.services['rest'].restCall('GET', `${BASE}/users/imports`, params);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('import-details')
            .argument('<reqId>', 'import request ID')
            .description('Get details of a user import job')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (reqId, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('GET', `${BASE}/users/imports/${reqId}/details`); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('import-content')
            .argument('<reqId>', 'import request ID')
            .argument('[filename]', 'save content to file')
            .description('Get the CSV content of a user import job')
            .action(async (reqId, filename) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const result = await this.services['rest'].get(`${BASE}/users/imports/${reqId}/content`);
                        const text = await result.text();
                        if (filename) {
                            await import('fs').then(m => m.promises.writeFile(filename, text, 'utf-8'));
                            return `Content saved to ${filename}`;
                        }
                        return text;
                    },
                    (msg) => { console.log(msg); }
                );
            });

        masspro
            .command('import-delete')
            .argument('<reqId>', 'import request ID')
            .description('Delete a user import job report')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (reqId, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('DELETE', `${BASE}/users/imports/${reqId}/details`); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('export')
            .argument('[filename]', 'output filename', 'users-export.csv')
            .description('Export users to a CSV file')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('--deleted', 'export deleted users instead'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = await this._baseParamsWithFallback(options);
                        const endpoint = options.deleted ? `${BASE}/users/export-deleted` : `${BASE}/users/export`;
                        return await this._downloadCSV(endpoint, params, filename);
                    },
                    (msg) => { console.log(msg); }
                );
            });

        masspro
            .command('synchronize-check')
            .argument('<filename>', 'CSV file to check before synchronization')
            .description('Validate a CSV file before user synchronization')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = await this._csvParamsWithFallback(options);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/users/imports/synchronize/check`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('synchronize')
            .argument('<filename>', 'CSV file to synchronize')
            .description('Synchronize users from a CSV file')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('--noemails', 'disable notification emails'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = await this._csvParamsWithFallback(options);
                        if (options.noemails) params.push(['noemails', true]);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/users/imports/synchronize`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('synchronize-report')
            .argument('<commandId>', 'synchronize command ID')
            .description('Get report for a user synchronize job')
            .addOption(new Option('--check', 'get the pre-sync check report'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (commandId, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const endpoint = options.check
                            ? `${BASE}/users/imports/synchronize/check/${commandId}/report`
                            : `${BASE}/users/imports/synchronize/${commandId}/report`;
                        return await this.services['rest'].restCall('GET', endpoint);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('about')
            .description('Display mass provisioning portal information')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('GET', `${BASE}/about`); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        masspro
            .command('ping')
            .description('Check mass provisioning service health')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('GET', '/api/rainbow/ping'); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        // ── DIRECTORIES ──────────────────────────────────────────────────────

        const dirCmd = masspro
            .command('dir')
            .description('Mass provisioning — directories');

        dirCmd
            .command('template')
            .argument('[filename]', 'output filename', 'dir-template.csv')
            .description('Download directory import CSV template')
            .action(async (filename) => {
                PrettyPrint.withSpinner(
                    async () => { return await this._downloadCSV(`${BASE}/directories/template`, [], filename); },
                    (msg) => { console.log(msg); }
                );
            });

        dirCmd
            .command('check')
            .argument('<filename>', 'CSV file to check')
            .description('Validate a directory CSV file')
            .addOption(new Option('-c, --company <id>', 'company ID (omit for personal directory)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = this._csvParams(options);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/directories/imports/check`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        dirCmd
            .command('import')
            .argument('<filename>', 'CSV file to import')
            .description('Import entries into a directory')
            .addOption(new Option('-c, --company <id>', 'company ID (omit for personal directory)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = this._csvParams(options);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/directories/imports`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        dirCmd
            .command('status')
            .description('Get directory import status')
            .addOption(new Option('-c, --company <id>', 'company ID (omit for personal directory)'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const endpoint = options.company
                            ? `${BASE}/directories/imports/${options.company}`
                            : `${BASE}/directories/imports/personal`;
                        return await this.services['rest'].restCall('GET', endpoint);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        dirCmd
            .command('details')
            .description('Get directory import report details')
            .addOption(new Option('-c, --company <id>', 'company ID (omit for personal directory)'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const endpoint = options.company
                            ? `${BASE}/directories/imports/${options.company}/details`
                            : `${BASE}/directories/imports/personal/details`;
                        return await this.services['rest'].restCall('GET', endpoint);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        dirCmd
            .command('delete')
            .description('Delete directory import report')
            .addOption(new Option('-c, --company <id>', 'company ID (omit for personal directory)'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const endpoint = options.company
                            ? `${BASE}/directories/imports/${options.company}`
                            : `${BASE}/directories/imports/personal`;
                        return await this.services['rest'].restCall('DELETE', endpoint);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        dirCmd
            .command('synchronize-check')
            .argument('<filename>', 'CSV file to check')
            .description('Validate a CSV file before directory synchronization')
            .addOption(new Option('-c, --company <id>', 'company ID (omit for personal directory)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = this._csvParams(options);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/directories/imports/synchronize/check`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        dirCmd
            .command('synchronize')
            .argument('<filename>', 'CSV file to synchronize')
            .description('Synchronize directory entries from a CSV file')
            .addOption(new Option('-c, --company <id>', 'company ID (omit for personal directory)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = this._csvParams(options);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/directories/imports/synchronize`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        dirCmd
            .command('synchronize-report')
            .argument('<commandId>', 'synchronize command ID')
            .description('Get report for a directory synchronize job')
            .addOption(new Option('--check', 'get the pre-sync check report'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (commandId, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const endpoint = options.check
                            ? `${BASE}/directories/imports/synchronize/check/${commandId}/report`
                            : `${BASE}/directories/imports/synchronize/${commandId}/report`;
                        return await this.services['rest'].restCall('GET', endpoint);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        // ── SIP DEVICES ──────────────────────────────────────────────────────

        const sipCmd = masspro
            .command('sip')
            .description('Mass provisioning — SIP devices');

        sipCmd
            .command('template')
            .argument('[filename]', 'output filename', 'sip-template.csv')
            .description('Download SIP device import CSV template')
            .action(async (filename) => {
                PrettyPrint.withSpinner(
                    async () => { return await this._downloadCSV(`${BASE}/sipdevices/template`, [], filename); },
                    (msg) => { console.log(msg); }
                );
            });

        sipCmd
            .command('check')
            .argument('<filename>', 'CSV file to check')
            .description('Validate a SIP device CSV file')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = await this._csvParamsWithFallback(options);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/sipdevices/check`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        sipCmd
            .command('import')
            .argument('<filename>', 'CSV file to import')
            .description('Import SIP devices from a CSV file')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = await this._csvParamsWithFallback(options);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/sipdevices/imports`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        sipCmd
            .command('imports')
            .description('List SIP device import jobs')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = await this._baseParamsWithFallback(options);
                        return await this.services['rest'].restCall('GET', `${BASE}/sipdevices/imports`, params);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        sipCmd
            .command('details')
            .argument('<reqId>', 'import request ID')
            .description('Get details of a SIP device import job')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (reqId, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('GET', `${BASE}/sipdevices/imports/${reqId}/details`); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        sipCmd
            .command('delete')
            .argument('<reqId>', 'import request ID')
            .description('Delete a SIP device import report')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (reqId, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('DELETE', `${BASE}/sipdevices/imports/${reqId}/details`); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        // ── ORG CHARTS ───────────────────────────────────────────────────────

        const orgCmd = masspro
            .command('org')
            .description('Mass provisioning — org charts');

        orgCmd
            .command('import')
            .argument('<filename>', 'CSV file to import')
            .description('Import an org chart from a CSV file')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const companyId = options.company || await this._getMyCompanyId();
                        const params = [['companyId', companyId]];
                        if (options.delimiter) params.push(['delimiter', options.delimiter]);
                        if (options.comment) params.push(['comment', options.comment]);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/orgcharts/imports`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        orgCmd
            .command('status')
            .description('Get org chart import status')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const companyId = options.company || await this._getMyCompanyId();
                        return await this.services['rest'].restCall('GET', `${BASE}/orgcharts/imports/${companyId}`);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        orgCmd
            .command('details')
            .description('Get org chart import report')
            .addOption(new Option('-c, --company <id>', 'company ID (default: current user company)'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const companyId = options.company || await this._getMyCompanyId();
                        return await this.services['rest'].restCall('GET', `${BASE}/orgcharts/imports/${companyId}/details`);
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        // ── WEBINARS ─────────────────────────────────────────────────────────

        const webinarCmd = masspro
            .command('webinar')
            .description('Mass provisioning — webinar participants');

        webinarCmd
            .command('template')
            .argument('[filename]', 'output filename', 'webinar-participants-template.csv')
            .description('Download webinar participants CSV template')
            .action(async (filename) => {
                PrettyPrint.withSpinner(
                    async () => { return await this._downloadCSV(`${BASE}/webinars/participants/template`, [], filename); },
                    (msg) => { console.log(msg); }
                );
            });

        webinarCmd
            .command('check')
            .argument('<webinarId>', 'webinar ID')
            .argument('<filename>', 'CSV file to check')
            .description('Validate a webinar participants CSV file')
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (webinarId, filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = [['webinarId', webinarId]];
                        if (options.delimiter) params.push(['delimiter', options.delimiter]);
                        if (options.comment) params.push(['comment', options.comment]);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/webinars/participants/imports/check`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        webinarCmd
            .command('import')
            .argument('<webinarId>', 'webinar ID')
            .argument('<filename>', 'CSV file to import')
            .description('Import participants into a webinar')
            .addOption(new Option('--delimiter <delimiter>', 'CSV delimiter'))
            .addOption(new Option('--comment <comment>', 'comment line prefix'))
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (webinarId, filename, options) => {
                PrettyPrint.withSpinner(
                    async () => {
                        const params = [['webinarId', webinarId]];
                        if (options.delimiter) params.push(['delimiter', options.delimiter]);
                        if (options.comment) params.push(['comment', options.comment]);
                        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
                        return await this.services['rest'].restCall('POST', `${BASE}/webinars/participants/imports`, params, data, { 'content-type': 'text/csv' });
                    },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        webinarCmd
            .command('status')
            .argument('<webinarId>', 'webinar ID')
            .description('Get webinar participants import status')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (webinarId, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('GET', `${BASE}/webinars/participants/imports/${webinarId}`); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        webinarCmd
            .command('details')
            .argument('<webinarId>', 'webinar ID')
            .description('Get webinar participants import report')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (webinarId, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('GET', `${BASE}/webinars/participants/imports/${webinarId}/details`); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });

        webinarCmd
            .command('delete')
            .argument('<webinarId>', 'webinar ID')
            .description('Delete webinar participants import')
            .addOption(new Option('-j, --json', 'display raw JSON'))
            .action(async (webinarId, options) => {
                PrettyPrint.withSpinner(
                    async () => { return await this.services['rest'].restCall('DELETE', `${BASE}/webinars/participants/imports/${webinarId}`); },
                    (json) => { PrettyPrint.display(json, undefined, options.json); }
                );
            });
    }

    // ── Helpers ───────────────────────────────────────────────────────────────

    _baseParams(options) {
        const params = [];
        if (options.company) params.push(['companyId', options.company]);
        return params;
    }

    _csvParams(options) {
        const params = this._baseParams(options);
        if (options.delimiter) params.push(['delimiter', options.delimiter]);
        if (options.comment) params.push(['comment', options.comment]);
        return params;
    }

    async _getMyCompanyId() {
        this.logger.debug('MassPro._getMyCompanyId');
        const me = await this.services['rest'].restCall('GET', '/api/rainbow/enduser/v1.0/users/me');
        return me?.data?.companyId;
    }

    // Variantes async qui résolvent le companyId depuis l'utilisateur connecté
    // quand --company n'est pas fourni. À utiliser pour tous les contextes NON-directory
    // (pour dir, l'absence de companyId cible le répertoire personnel — pas de fallback).
    async _baseParamsWithFallback(options) {
        const companyId = options.company || await this._getMyCompanyId();
        return companyId ? [['companyId', companyId]] : [];
    }

    async _csvParamsWithFallback(options) {
        const params = await this._baseParamsWithFallback(options);
        if (options.delimiter) params.push(['delimiter', options.delimiter]);
        if (options.comment) params.push(['comment', options.comment]);
        return params;
    }

    async _downloadCSV(endpoint, params, filename) {
        this.logger.debug('MassPro._downloadCSV');
        const result = await this.services['rest'].get(endpoint, params);
        const text = await result.text();
        await import('fs').then(m => m.promises.writeFile(filename, text, 'utf-8'));
        return `Template saved to ${filename}`;
    }

    async _checkCSV(filename, options) {
        this.logger.debug('MassPro._checkCSV');
        const params = await this._csvParamsWithFallback(options);
        const endpoints = {
            'user':          `${BASE}/users/imports/check`,
            'device':        `${BASE}/users/imports/check`,
            'useranddevice': `${BASE}/users/imports/synchronize/check`,
            'rainbowvoice':  `${BASE}/users/imports/rainbowvoice/check`,
        };
        const endpoint = endpoints[options.type] ?? endpoints['user'];
        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
        return await this.services['rest'].restCall('POST', endpoint, params, data, { 'content-type': 'text/csv' });
    }

    async _importCSV(filename, options) {
        this.logger.debug('MassPro._importCSV');
        const params = await this._csvParamsWithFallback(options);
        if (options.noemails) params.push(['noemails', true]);
        if (options.nostrict) params.push(['nostrict', true]);
        const endpoints = {
            'user':          `${BASE}/users/imports`,
            'device':        `${BASE}/users/imports`,
            'useranddevice': `${BASE}/users/imports/synchronize`,
            'rainbowvoice':  `${BASE}/users/imports/rainbowvoice`,
        };
        const endpoint = endpoints[options.type] ?? endpoints['user'];
        const data = await import('fs').then(m => m.promises.readFile(filename, 'utf-8'));
        return await this.services['rest'].restCall('POST', endpoint, params, data, { 'content-type': 'text/csv' });
    }
}
