/**
 * CleanupScheduler
 *
 * Daily cleanup of old JobRun records
 * - Deletes successful jobs older than 2 weeks
 * - Keeps failed/partial jobs indefinitely for debugging
 */

import { PrismaClient } from '@prisma/client';
import { DateTime } from 'luxon';
import logger from '../utils/logger';
import { BaseScheduler } from './base-scheduler';
import { ScheduleType, JobContext, JobResult } from './types';
import { SCHEDULER_CONFIGS } from './config';

export class CleanupScheduler extends BaseScheduler {
  // Retention period for successful jobs (in days)
  private readonly SUCCESSFUL_RETENTION_DAYS = 14;

  constructor(prisma: PrismaClient) {
    super(ScheduleType.CLEANUP_JOB_RUNS, SCHEDULER_CONFIGS[ScheduleType.CLEANUP_JOB_RUNS], prisma);
  }

  protected async executeJob(_context: JobContext): Promise<JobResult> {
    const startTime = Date.now();
    const result: JobResult = {
      success: true,
      itemsProcessed: 0,
      durationMs: 0,
      errors: [],
      metadata: {
        deletedSuccessful: 0,
        keptFailed: 0,
        keptPartial: 0,
        cutoffDate: '',
      },
    };

    try {
      // Calculate cutoff date (2 weeks ago)
      const cutoffDate = DateTime.now()
        .toUTC()
        .minus({ days: this.SUCCESSFUL_RETENTION_DAYS })
        .toJSDate();

      result.metadata!.cutoffDate = cutoffDate.toISOString();

      logger.info({
        cutoffDate: cutoffDate.toISOString(),
        retentionDays: this.SUCCESSFUL_RETENTION_DAYS,
      }, 'Starting JobRun cleanup');

      // Count jobs that will be kept (for logging)
      const keptFailed = await this.prisma.jobRun.count({
        where: {
          status: 'failed',
          startedAt: { lt: cutoffDate },
        },
      });

      const keptPartial = await this.prisma.jobRun.count({
        where: {
          status: 'partial',
          startedAt: { lt: cutoffDate },
        },
      });

      result.metadata!.keptFailed = keptFailed;
      result.metadata!.keptPartial = keptPartial;

      // Delete successful jobs older than cutoff
      // Note: Cascading will also delete related Scrape records if configured
      const deleteResult = await this.prisma.jobRun.deleteMany({
        where: {
          status: 'success',
          startedAt: { lt: cutoffDate },
        },
      });

      result.metadata!.deletedSuccessful = deleteResult.count;
      result.itemsProcessed = deleteResult.count;

      logger.info({
        deleted: deleteResult.count,
        keptFailed,
        keptPartial,
        cutoffDate: cutoffDate.toISOString(),
      }, 'JobRun cleanup completed');

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';

      logger.error({
        error: errorMessage,
        stack: error instanceof Error ? error.stack : undefined,
      }, 'JobRun cleanup failed');

      result.success = false;
      result.errors.push(`Cleanup failed: ${errorMessage}`);
    }

    result.durationMs = Date.now() - startTime;
    return result;
  }
}
