/**
* Professional Report Generator
* Creates comprehensive reports in multiple formats (PPT, Word, HTML, PDF)
*/
import { Client } from '@microsoft/microsoft-graph-client';
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import {
ProfessionalReportArgs,
DataQuery,
PowerPointSlide,
WordSection,
HTMLSection,
ChartData,
TableData
} from '../types/document-generation-types.js';
import { handlePowerPointPresentations } from './powerpoint-handler.js';
import { handleWordDocuments } from './word-document-handler.js';
import { handleHTMLReports } from './html-report-handler.js';
/**
* Generate professional reports in multiple formats
*/
export async function handleProfessionalReports(
args: ProfessionalReportArgs,
graphClient: Client
): Promise<string> {
try {
// Step 1: Collect data from specified sources
const collectedData = await collectReportData(args.dataQueries || [], graphClient);
// Step 2: Generate report content based on report type
const reportContent = generateReportContent(args, collectedData);
// Step 3: Create documents in requested formats
const createdFiles = [];
for (const format of args.outputFormats) {
let result;
switch (format) {
case 'pptx':
result = await createPowerPointReport(args, reportContent, graphClient);
createdFiles.push({ format: 'pptx', ...result });
break;
case 'docx':
result = await createWordReport(args, reportContent, graphClient);
createdFiles.push({ format: 'docx', ...result });
break;
case 'html':
result = await createHTMLReport(args, reportContent, graphClient);
createdFiles.push({ format: 'html', ...result });
break;
case 'pdf':
// PDF is generated by first creating Word and then converting
result = await createPDFReport(args, reportContent, graphClient);
createdFiles.push({ format: 'pdf', ...result });
break;
}
}
return JSON.stringify({
success: true,
reportType: args.reportType,
title: args.title,
filesCreated: createdFiles.length,
files: createdFiles,
dataSourcesQueried: args.dataQueries?.length || 0,
message: `Professional report "${args.title}" generated successfully in ${createdFiles.length} format(s)`
}, null, 2);
} catch (error) {
if (error instanceof McpError) throw error;
throw new McpError(
ErrorCode.InternalError,
`Professional report generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
/**
* Collect data from Microsoft Graph API sources
*/
async function collectReportData(
queries: DataQuery[],
graphClient: Client
): Promise<Map<string, any>> {
const dataMap = new Map<string, any>();
for (const query of queries) {
try {
let response = await graphClient.api(query.endpoint).get();
// Apply filter if specified
if (query.filter) {
response = await graphClient.api(query.endpoint).filter(query.filter).get();
}
// Apply select if specified
if (query.select && query.select.length > 0) {
response = await graphClient.api(query.endpoint).select(query.select).get();
}
// Apply transformation if specified
let transformedData = response.value || response;
if (query.transform) {
transformedData = applyTransformation(transformedData, query.transform);
}
dataMap.set(query.label, transformedData);
} catch (error) {
console.error(`Failed to query ${query.endpoint}:`, error);
dataMap.set(query.label, { error: 'Failed to fetch data' });
}
}
return dataMap;
}
/**
* Apply data transformation
*/
function applyTransformation(data: any[], transform: string): any {
switch (transform) {
case 'count':
return { count: Array.isArray(data) ? data.length : 0 };
case 'group-by':
// Group by first property
if (!Array.isArray(data) || data.length === 0) return {};
const groupKey = Object.keys(data[0])[0];
return data.reduce((acc: any, item) => {
const key = item[groupKey];
acc[key] = (acc[key] || 0) + 1;
return acc;
}, {});
case 'aggregate':
// Sum numeric values
if (!Array.isArray(data)) return data;
return data.reduce((acc, item) => {
Object.keys(item).forEach(key => {
if (typeof item[key] === 'number') {
acc[key] = (acc[key] || 0) + item[key];
}
});
return acc;
}, {});
case 'trend':
// Create time-series data (simplified)
return Array.isArray(data) ? { dataPoints: data.length, trend: 'stable' } : data;
default:
return data;
}
}
/**
* Generate report content structure
*/
function generateReportContent(
args: ProfessionalReportArgs,
collectedData: Map<string, any>
): ReportContent {
const content: ReportContent = {
title: args.title,
description: args.description || '',
sections: [],
charts: [],
tables: [],
summary: ''
};
// Generate executive summary if requested
if (args.includeSummary) {
content.summary = generateExecutiveSummary(args, collectedData);
}
// Generate sections based on report type
switch (args.reportType) {
case 'security-analysis':
content.sections = generateSecurityAnalysisSections(collectedData);
break;
case 'compliance-audit':
content.sections = generateComplianceAuditSections(collectedData);
break;
case 'user-activity':
content.sections = generateUserActivitySections(collectedData);
break;
case 'device-health':
content.sections = generateDeviceHealthSections(collectedData);
break;
case 'custom':
content.sections = generateCustomSections(collectedData);
break;
}
// Extract charts and tables if requested
if (args.includeCharts) {
content.charts = extractChartsFromData(collectedData);
}
if (args.includeTables) {
content.tables = extractTablesFromData(collectedData);
}
return content;
}
/**
* Generate executive summary
*/
function generateExecutiveSummary(
args: ProfessionalReportArgs,
data: Map<string, any>
): string {
let summary = `This ${args.reportType} report provides a comprehensive analysis of `;
summary += `the current state based on data collected from ${data.size} sources. `;
summary += `Key findings and recommendations are detailed in the following sections.`;
return summary;
}
/**
* Generate sections for security analysis report
*/
function generateSecurityAnalysisSections(data: Map<string, any>): ReportSection[] {
const sections: ReportSection[] = [
{
title: 'Security Overview',
content: 'Analysis of current security posture and identified risks.',
type: 'overview'
},
{
title: 'Threat Detection',
content: 'Summary of detected threats and security incidents.',
type: 'analysis'
},
{
title: 'Recommendations',
content: 'Recommended actions to improve security.',
type: 'recommendations'
}
];
return sections;
}
/**
* Generate sections for compliance audit report
*/
function generateComplianceAuditSections(data: Map<string, any>): ReportSection[] {
return [
{ title: 'Compliance Status', content: 'Current compliance state', type: 'overview' },
{ title: 'Policy Violations', content: 'Identified policy violations', type: 'findings' },
{ title: 'Remediation Plan', content: 'Steps to achieve compliance', type: 'action-plan' }
];
}
/**
* Generate sections for user activity report
*/
function generateUserActivitySections(data: Map<string, any>): ReportSection[] {
return [
{ title: 'User Activity Summary', content: 'Overview of user activities', type: 'overview' },
{ title: 'Top Users', content: 'Most active users', type: 'analysis' },
{ title: 'Activity Trends', content: 'Usage trends over time', type: 'trends' }
];
}
/**
* Generate sections for device health report
*/
function generateDeviceHealthSections(data: Map<string, any>): ReportSection[] {
return [
{ title: 'Device Inventory', content: 'Current device inventory', type: 'overview' },
{ title: 'Health Status', content: 'Device health metrics', type: 'analysis' },
{ title: 'Issues & Recommendations', content: 'Identified issues', type: 'recommendations' }
];
}
/**
* Generate custom sections
*/
function generateCustomSections(data: Map<string, any>): ReportSection[] {
const sections: ReportSection[] = [];
data.forEach((value, key) => {
sections.push({
title: key,
content: JSON.stringify(value, null, 2),
type: 'data'
});
});
return sections;
}
/**
* Extract charts from collected data
*/
function extractChartsFromData(data: Map<string, any>): ChartData[] {
const charts: ChartData[] = [];
data.forEach((value, label) => {
if (typeof value === 'object' && value !== null) {
// Try to create a chart from the data
const keys = Object.keys(value);
if (keys.length > 0 && typeof value[keys[0]] === 'number') {
charts.push({
type: 'bar',
title: label,
categories: keys,
series: [{
name: label,
values: keys.map(k => value[k])
}]
});
}
}
});
return charts;
}
/**
* Extract tables from collected data
*/
function extractTablesFromData(data: Map<string, any>): TableData[] {
const tables: TableData[] = [];
data.forEach((value, label) => {
if (Array.isArray(value) && value.length > 0) {
const firstItem = value[0];
if (typeof firstItem === 'object') {
const headers = Object.keys(firstItem);
const rows = value.map(item => headers.map(h => String(item[h] || '')));
tables.push({
headers: headers,
rows: rows
});
}
}
});
return tables;
}
/**
* Create PowerPoint report
*/
async function createPowerPointReport(
args: ProfessionalReportArgs,
content: ReportContent,
graphClient: Client
): Promise<any> {
const slides: PowerPointSlide[] = [
// Title slide
{
type: 'title',
title: content.title,
subtitle: content.description
},
// Summary slide
...(content.summary ? [{
type: 'title-content' as const,
title: 'Executive Summary',
content: [content.summary]
}] : []),
// Content slides
...content.sections.map(section => ({
type: 'title-content' as const,
title: section.title,
content: [section.content]
})),
// Chart slides
...content.charts.map(chart => ({
type: 'chart' as const,
title: chart.title,
chartData: chart
}))
];
const fileName = `${args.fileNamePrefix || args.title}_${Date.now()}.pptx`;
const result = await handlePowerPointPresentations(
{
action: 'create',
fileName: fileName,
driveId: args.driveId,
folderId: args.folderId,
slides: slides,
template: {
theme: 'professional',
companyName: args.template?.companyName,
companyLogo: args.template?.companyLogo
}
},
graphClient
);
return JSON.parse(result);
}
/**
* Create Word report
*/
async function createWordReport(
args: ProfessionalReportArgs,
content: ReportContent,
graphClient: Client
): Promise<any> {
const sections: WordSection[] = [
// Title
{ type: 'heading1' as const, content: content.title },
...(content.description ? [{ type: 'paragraph' as const, content: content.description }] : []),
// Summary
...(content.summary ? [
{ type: 'heading2' as const, content: 'Executive Summary' },
{ type: 'paragraph' as const, content: content.summary }
] : []),
// Content sections
...content.sections.flatMap(section => [
{ type: 'heading2' as const, content: section.title },
{ type: 'paragraph' as const, content: section.content }
]),
// Tables
...content.tables.map(table => ({
type: 'table' as const,
tableData: table
}))
];
const fileName = `${args.fileNamePrefix || args.title}_${Date.now()}.docx`;
const result = await handleWordDocuments(
{
action: 'create',
fileName: fileName,
driveId: args.driveId,
folderId: args.folderId,
sections: sections,
template: {
style: 'report',
header: args.template?.companyName,
footer: `${content.title} - Page `,
pageNumbers: true,
tableOfContents: true
}
},
graphClient
);
return JSON.parse(result);
}
/**
* Create HTML report
*/
async function createHTMLReport(
args: ProfessionalReportArgs,
content: ReportContent,
graphClient: Client
): Promise<any> {
const htmlSections: HTMLSection[] = [
// Summary
...(content.summary ? [{
type: 'alert' as const,
alertType: 'info' as const,
heading: 'Executive Summary',
content: content.summary
}] : []),
// Content sections
...content.sections.map(section => ({
type: 'heading' as const,
level: 2 as const,
heading: section.title,
content: section.content
})),
// Charts
...content.charts.map(chart => ({
type: 'chart' as const,
chartData: chart
})),
// Tables
...content.tables.map(table => ({
type: 'table' as const,
tableData: table
}))
];
const fileName = `${args.fileNamePrefix || args.title}_${Date.now()}.html`;
const result = await handleHTMLReports(
{
action: 'create',
fileName: fileName,
driveId: args.driveId,
folderId: args.folderId,
template: {
title: content.title,
description: content.description,
theme: 'modern',
companyName: args.template?.companyName,
companyLogo: args.template?.companyLogo,
includeBootstrap: true,
includeChartJS: true
},
sections: htmlSections,
includeCharts: true
},
graphClient
);
return JSON.parse(result);
}
/**
* Create PDF report (by converting Word document)
*/
async function createPDFReport(
args: ProfessionalReportArgs,
content: ReportContent,
graphClient: Client
): Promise<any> {
// First create Word document
const wordResult = await createWordReport(args, content, graphClient);
// Then export to PDF
const pdfFileName = `${args.fileNamePrefix || args.title}_${Date.now()}.pdf`;
// Note: Actual PDF conversion would use Word's export API
return {
...wordResult,
format: 'pdf',
fileName: pdfFileName,
note: 'PDF generated from Word document via export API'
};
}
// Type definitions for report content
interface ReportContent {
title: string;
description: string;
sections: ReportSection[];
charts: ChartData[];
tables: TableData[];
summary: string;
}
interface ReportSection {
title: string;
content: string;
type: string;
}