import { DOMParser } from '@xmldom/xmldom';
import { z } from 'zod';
import { cli } from '../../../../cli/cli.js';
import { globalOptionsZod } from '../../../../Command.js';
import request from '../../../../request.js';
import { md } from '../../../../utils/md.js';
import { validation } from '../../../../utils/validation.js';
import { zod } from '../../../../utils/zod.js';
import AnonymousCommand from '../../../base/AnonymousCommand.js';
import commands from '../../commands.js';
const allowedVersions = ['beta', 'v1.0'];
var ChangeType;
(function (ChangeType) {
    ChangeType["Addition"] = "Addition";
    ChangeType["Change"] = "Change";
    ChangeType["Deletion"] = "Deletion";
    ChangeType["Deprecation"] = "Deprecation";
})(ChangeType || (ChangeType = {}));
const allowedServices = [
    'Applications', 'Calendar', 'Change notifications', 'Cloud communications',
    'Compliance', 'Cross-device experiences', 'Customer booking', 'Device and app management',
    'Education', 'Files', 'Financials', 'Groups',
    'Identity and access', 'Mail', 'Notes', 'Notifications',
    'People and workplace intelligence', 'Personal contacts', 'Reports', 'Search',
    'Security', 'Sites and lists', 'Tasks and plans', 'Teamwork',
    'To-do tasks', 'Users', 'Workbooks and charts'
];
export const options = z.strictObject({
    ...globalOptionsZod.shape,
    versions: z.string().optional().alias('v'),
    changeType: zod.coercedEnum(ChangeType).optional().alias('c'),
    services: z.string().optional().alias('s'),
    startDate: z.string().optional(),
    endDate: z.string().optional()
});
class GraphChangelogListCommand extends AnonymousCommand {
    get name() {
        return commands.CHANGELOG_LIST;
    }
    get description() {
        return 'Gets an overview of specific API-level changes in Microsoft Graph v1.0 and beta';
    }
    defaultProperties() {
        return ['category', 'title', 'description'];
    }
    get schema() {
        return options;
    }
    getRefinedSchema(schema) {
        return schema
            .refine(options => {
            if (!options.versions) {
                return true;
            }
            return !options.versions.toLocaleLowerCase().split(',').some(x => !allowedVersions.map(y => y.toLocaleLowerCase()).includes(x));
        }, {
            error: `The versions contains an invalid value. Specify either ${allowedVersions.join(', ')} as properties`,
            path: ['versions']
        })
            .refine(options => {
            if (!options.services) {
                return true;
            }
            return !options.services.toLocaleLowerCase().split(',').some(x => !allowedServices.map(y => y.toLocaleLowerCase()).includes(x));
        }, {
            error: `The services contains invalid value. Specify either ${allowedServices.join(', ')} as properties`,
            path: ['services']
        })
            .refine(options => !options.startDate || validation.isValidISODate(options.startDate), {
            error: 'The startDate is not a valid ISO date string',
            path: ['startDate']
        })
            .refine(options => !options.endDate || validation.isValidISODate(options.endDate), {
            error: 'The endDate is not a valid ISO date string',
            path: ['endDate']
        })
            .refine(options => !(options.endDate && options.startDate && new Date(options.endDate) < new Date(options.startDate)), {
            error: 'The endDate should be later than startDate',
            path: ['endDate']
        });
    }
    async commandAction(logger, args) {
        try {
            const searchParam = args.options.changeType ? `/?filterBy=${args.options.changeType}` : '';
            const requestOptions = {
                url: `https://developer.microsoft.com/en-us/graph/changelog/rss${searchParam}`,
                headers: {
                    'accept': 'text/xml',
                    'x-anonymous': 'true'
                }
            };
            const output = await request.get(requestOptions);
            const parser = new DOMParser();
            const xmlDoc = parser.parseFromString(output.toString(), "text/xml");
            const changelog = this.filterThroughOptions(args.options, this.mapChangelog(xmlDoc, args));
            await logger.log(changelog.items);
        }
        catch (err) {
            this.handleRejectedODataJsonPromise(err);
        }
    }
    filterThroughOptions(options, changelog) {
        let items = changelog.items;
        if (options.services) {
            const matchedServices = allowedServices
                .filter(allowedService => options.services.toLocaleLowerCase().split(',').includes(allowedService.toLocaleLowerCase()));
            items = changelog.items.filter(item => matchedServices.includes(item.title));
        }
        if (options.versions) {
            const matchedVersions = allowedVersions
                .filter(allowedVersion => options.versions.toLocaleLowerCase().split(',').includes(allowedVersion.toLocaleLowerCase()));
            items = items.filter(item => matchedVersions.includes(item.category));
        }
        if (options.startDate) {
            const startDate = new Date(options.startDate);
            items = items.filter(item => item.pubDate >= startDate);
        }
        if (options.endDate) {
            const endDate = new Date(options.endDate);
            items = items.filter(item => item.pubDate <= endDate);
        }
        // Make sure everything is unique based on the item guid
        items = [...new Map(items.map((item) => [item.guid, item])).values()];
        changelog.items = items.sort((itemA, itemB) => Number(itemB.pubDate) - Number(itemA.pubDate));
        return changelog;
    }
    mapChangelog(xmlDoc, args) {
        const channel = xmlDoc.getElementsByTagName('channel').item(0);
        const changelog = {
            title: channel.getElementsByTagName('title').item(0).textContent,
            description: channel.getElementsByTagName('description').item(0).textContent,
            url: channel.getElementsByTagName('link').item(0).textContent,
            items: []
        };
        Array.from(xmlDoc.getElementsByTagName('item')).forEach((item) => {
            const description = cli.shouldTrimOutput(args.options.output) ?
                md.md2plain(item.getElementsByTagName('description').item(0).textContent, '') :
                item.getElementsByTagName('description').item(0).textContent;
            changelog.items.push({
                guid: item.getElementsByTagName('guid').item(0).textContent,
                category: item.getElementsByTagName('category').item(1).textContent,
                title: item.getElementsByTagName('title').item(0).textContent,
                description: cli.shouldTrimOutput(args.options.output) ?
                    description.length > 50 ? `${description.substring(0, 47)}...` : description :
                    description,
                pubDate: new Date(item.getElementsByTagName('pubDate').item(0).textContent)
            });
        });
        return changelog;
    }
}
export default new GraphChangelogListCommand();
//# sourceMappingURL=changelog-list.js.map