/**
 * Report Execution Scheduler
 * Manages scheduled report generation and email delivery
 */

import { ReportCustomization } from './reportCustomization';
import { sendReportEmail, createReportEmailJob, processEmailJob } from './reportEmailDelivery';

export interface ReportExecution {
  id: string;
  customizationId: string;
  executedAt: Date;
  status: 'pending' | 'executing' | 'completed' | 'failed';
  reportData?: any;
  emailJobId?: string;
  emailStatus?: 'pending' | 'sent' | 'failed';
  errorMessage?: string;
  executionTime: number;
  nextScheduledRun?: Date;
}

export interface ReportScheduleJob {
  id: string;
  customizationId: string;
  customization: ReportCustomization;
  lastExecution?: ReportExecution;
  nextExecution: Date;
  isActive: boolean;
}

/**
 * Calculate next execution time based on schedule
 */
export function calculateNextExecution(
  customization: ReportCustomization,
  lastExecution?: Date
): Date {
  const now = new Date();
  const [hours, minutes] = (customization.delivery.time || '09:00').split(':').map(Number);

  let nextRun = new Date(now);
  nextRun.setHours(hours, minutes, 0, 0);

  // If the time has already passed today, move to next period
  if (nextRun <= now) {
    switch (customization.delivery.frequency) {
      case 'daily':
        nextRun.setDate(nextRun.getDate() + 1);
        break;
      case 'weekly':
        nextRun.setDate(nextRun.getDate() + 7);
        break;
      case 'monthly':
        nextRun.setMonth(nextRun.getMonth() + 1);
        break;
      case 'once':
        return new Date(0); // No next execution
    }
  }

  return nextRun;
}

/**
 * Generate mock report data
 */
export function generateReportData(customization: ReportCustomization): any {
  const now = new Date();
  const summary: Record<string, any> = {};

  // Generate summary metrics based on report type
  switch (customization.type) {
    case 'payment':
      summary.totalRevenue = '$125,000';
      summary.totalTransactions = '2,500';
      summary.successRate = '94.5%';
      summary.averageTransaction = '$50';
      break;
    case 'reconciliation':
      summary.totalRecords = '5,000';
      summary.totalMatched = '4,950';
      summary.matchRate = '99%';
      summary.totalDiscrepancies = '50';
      break;
    case 'fraud':
      summary.totalAnalyzed = '2,500';
      summary.criticalCount = '5';
      summary.highCount = '25';
      summary.blockRate = '1.2%';
      break;
    case 'withdrawal':
      summary.totalWithdrawals = '500';
      summary.totalAmount = '$50,000';
      summary.approvedCount = '450';
      summary.pendingCount = '50';
      break;
    case 'analytics':
      summary.totalRevenue = '$125,000';
      summary.totalTransactions = '2,500';
      summary.successRate = '94.5%';
      summary.fraudRate = '1.2%';
      break;
  }

  return {
    type: customization.type,
    generatedAt: now.toISOString(),
    dateRange: {
      start: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(),
      end: now.toISOString(),
    },
    summary,
    details: {
      dailyBreakdown: generateDailyBreakdown(),
      paymentMethods: generatePaymentMethods(),
    },
    filters: customization.filters,
    metrics: customization.metrics,
  };
}

/**
 * Generate daily breakdown data
 */
function generateDailyBreakdown(): any[] {
  const data = [];
  for (let i = 6; i >= 0; i--) {
    const date = new Date();
    date.setDate(date.getDate() - i);
    data.push({
      date: date.toISOString().split('T')[0],
      revenue: `$${Math.floor(Math.random() * 30000) + 10000}`,
      transactions: Math.floor(Math.random() * 500) + 100,
      successRate: `${Math.floor(Math.random() * 10) + 90}%`,
    });
  }
  return data;
}

/**
 * Generate payment methods data
 */
function generatePaymentMethods(): any[] {
  return [
    { method: 'Square', count: 1200, amount: '$60,000', percentage: '48%' },
    { method: 'PayPal', count: 650, amount: '$32,500', percentage: '26%' },
    { method: 'Google Pay', count: 400, amount: '$20,000', percentage: '16%' },
    { method: 'Other', count: 250, amount: '$12,500', percentage: '10%' },
  ];
}

/**
 * Create report execution
 */
export function createReportExecution(
  customizationId: string,
  reportData: any
): ReportExecution {
  return {
    id: `EXEC-${Date.now()}`,
    customizationId,
    executedAt: new Date(),
    status: 'pending',
    reportData,
    executionTime: 0,
  };
}

/**
 * Execute report and send emails
 */
export async function executeReport(
  customization: ReportCustomization
): Promise<ReportExecution> {
  const execution = createReportExecution(customization.id, {});
  const startTime = Date.now();

  try {
    execution.status = 'executing';

    // Generate report data
    console.log(`[Report Execution] Generating report: ${customization.name}`);
    const reportData = generateReportData(customization);
    execution.reportData = reportData;

    // Create email job
    const emailJob = createReportEmailJob(
      customization.id,
      customization.recipients.emails,
      reportData,
      customization.delivery.format
    );
    execution.emailJobId = emailJob.id;

    // Send email
    console.log(`[Report Execution] Sending emails to ${emailJob.recipients.length} recipients`);
    const emailResult = await processEmailJob(emailJob);

    execution.emailStatus = emailResult.status as any;
    execution.status = emailResult.status === 'sent' ? 'completed' : 'failed';
    execution.errorMessage = emailResult.failureReason;

    // Calculate execution time
    execution.executionTime = (Date.now() - startTime) / 1000;

    // Calculate next execution
    if (customization.delivery.frequency !== 'once') {
      execution.nextScheduledRun = calculateNextExecution(customization, execution.executedAt);
    }

    console.log(`[Report Execution] Report execution completed: ${execution.id}`);
    console.log(`[Report Execution] Status: ${execution.status}, Time: ${execution.executionTime}s`);

    return execution;
  } catch (error) {
    console.error(`[Report Execution] Error executing report:`, error);
    execution.status = 'failed';
    execution.errorMessage = error instanceof Error ? error.message : 'Unknown error';
    execution.executionTime = (Date.now() - startTime) / 1000;

    return execution;
  }
}

/**
 * Create schedule job from customization
 */
export function createScheduleJob(customization: ReportCustomization): ReportScheduleJob {
  return {
    id: `JOB-${customization.id}`,
    customizationId: customization.id,
    customization,
    nextExecution: calculateNextExecution(customization),
    isActive: customization.enabled,
  };
}

/**
 * Get pending report executions
 */
export function getPendingReportExecutions(jobs: ReportScheduleJob[]): ReportScheduleJob[] {
  const now = new Date();
  return jobs.filter(job => job.isActive && job.nextExecution <= now);
}

/**
 * Update schedule job after execution
 */
export function updateScheduleJobAfterExecution(
  job: ReportScheduleJob,
  execution: ReportExecution
): ReportScheduleJob {
  return {
    ...job,
    lastExecution: execution,
    nextExecution: calculateNextExecution(job.customization, execution.executedAt),
  };
}

/**
 * Batch execute pending reports
 */
export async function batchExecutePendingReports(
  jobs: ReportScheduleJob[]
): Promise<{ executed: ReportExecution[]; failed: string[] }> {
  const pendingJobs = getPendingReportExecutions(jobs);
  const executed: ReportExecution[] = [];
  const failed: string[] = [];

  console.log(`[Report Execution] Processing ${pendingJobs.length} pending reports`);

  for (const job of pendingJobs) {
    try {
      const execution = await executeReport(job.customization);
      executed.push(execution);

      if (execution.status === 'failed') {
        failed.push(job.customizationId);
      }
    } catch (error) {
      console.error(`[Report Execution] Error executing job ${job.id}:`, error);
      failed.push(job.customizationId);
    }
  }

  console.log(`[Report Execution] Batch execution completed: ${executed.length} executed, ${failed.length} failed`);

  return { executed, failed };
}

/**
 * Get execution statistics
 */
export interface ExecutionStats {
  totalExecutions: number;
  successfulExecutions: number;
  failedExecutions: number;
  successRate: number;
  averageExecutionTime: number;
  totalEmailsSent: number;
  failedEmails: number;
}

export function getExecutionStats(executions: ReportExecution[]): ExecutionStats {
  const successful = executions.filter(e => e.status === 'completed').length;
  const failed = executions.filter(e => e.status === 'failed').length;
  const executionTimes = executions.map(e => e.executionTime);

  return {
    totalExecutions: executions.length,
    successfulExecutions: successful,
    failedExecutions: failed,
    successRate: executions.length > 0 ? (successful / executions.length) * 100 : 0,
    averageExecutionTime: executionTimes.length > 0 ? executionTimes.reduce((a, b) => a + b) / executionTimes.length : 0,
    totalEmailsSent: executions.filter(e => e.emailStatus === 'sent').length,
    failedEmails: executions.filter(e => e.emailStatus === 'failed').length,
  };
}

/**
 * Schedule report execution at specific time
 */
export function scheduleReportExecution(
  customization: ReportCustomization,
  executionTime: Date
): { job: ReportScheduleJob; scheduledFor: Date } {
  const job = createScheduleJob(customization);

  return {
    job: {
      ...job,
      nextExecution: executionTime,
    },
    scheduledFor: executionTime,
  };
}

/**
 * Get execution history for customization
 */
export function getExecutionHistory(
  customizationId: string,
  executions: ReportExecution[],
  limit: number = 20
): ReportExecution[] {
  return executions
    .filter(e => e.customizationId === customizationId)
    .sort((a, b) => b.executedAt.getTime() - a.executedAt.getTime())
    .slice(0, limit);
}

/**
 * Retry failed report execution
 */
export async function retryFailedExecution(
  customization: ReportCustomization,
  failedExecution: ReportExecution
): Promise<ReportExecution> {
  console.log(`[Report Execution] Retrying failed execution: ${failedExecution.id}`);

  // Re-execute the report
  const newExecution = await executeReport(customization);

  return newExecution;
}

/**
 * Cancel scheduled report
 */
export function cancelScheduledReport(job: ReportScheduleJob): ReportScheduleJob {
  return {
    ...job,
    isActive: false,
  };
}

/**
 * Resume scheduled report
 */
export function resumeScheduledReport(job: ReportScheduleJob): ReportScheduleJob {
  return {
    ...job,
    isActive: true,
    nextExecution: calculateNextExecution(job.customization),
  };
}
