import { prisma, SubscriptionTier, SubscriptionStatus } from '@shieldsai/shared-db';
import { tierConfig } from '@shieldsai/shared-billing';
import { darkwatchScanQueue } from '@shieldsai/jobs';
import { randomUUID } from 'crypto';

const CRON_EXPRESSIONS = {
  daily: '0 0 * * *',
  hourly: '0 * * * *',
  realtime: null,
};

export class SchedulerService {
  async scheduleSubscriptionScans() {
    const activeSubscriptions = await prisma.subscription.findMany({
      where: {
        tier: { in: [SubscriptionTier.basic, SubscriptionTier.plus, SubscriptionTier.premium] },
        status: SubscriptionStatus.active,
      },
      select: {
        id: true,
        tier: true,
        userId: true,
      },
    });

    const jobsEnqueued = [];

    for (const subscription of activeSubscriptions) {
      const frequency = tierConfig[subscription.tier].features.darkWebScanFrequency;
      const cron = CRON_EXPRESSIONS[frequency];

      if (!cron) {
        continue;
      }

      const jobKey = `scheduled-scan:${subscription.id}`;

      try {
        await darkwatchScanQueue.add(
          'scheduled-scan',
          {
            subscriptionId: subscription.id,
            tier: subscription.tier,
            scanType: 'scheduled',
          },
          {
            jobId: jobKey,
            repeat: {
              every: frequency === 'daily'
                ? 24 * 60 * 60 * 1000
                : 60 * 60 * 1000,
            },
            priority: subscription.tier === SubscriptionTier.premium ? 1 : 3,
          }
        );

        jobsEnqueued.push({
          subscriptionId: subscription.id,
          tier: subscription.tier,
          frequency,
        });
      } catch (error) {
        if ((error as Error).message?.includes('Duplicate')) {
          continue;
        }
        console.error(
          `[SchedulerService] Failed to schedule scan for ${subscription.id}:`,
          error
        );
      }
    }

    return jobsEnqueued;
  }

  async enqueueOnDemandScan(subscriptionId: string) {
    const subscription = await prisma.subscription.findUnique({
      where: { id: subscriptionId },
      select: { id: true, tier: true },
    });

    if (!subscription) {
      throw new Error(`Subscription ${subscriptionId} not found`);
    }

    return darkwatchScanQueue.add(
      'on-demand-scan',
      {
        subscriptionId,
        tier: subscription.tier,
        scanType: 'on-demand',
      },
      {
        priority: 1,
        jobId: `on-demand-scan:${subscriptionId}:${randomUUID()}`,
      }
    );
  }

  async enqueueRealtimeTrigger(subscriptionId: string, sourceData: Record<string, unknown>) {
    const subscription = await prisma.subscription.findUnique({
      where: { id: subscriptionId },
      select: { id: true, tier: true },
    });

    if (!subscription || subscription.tier !== SubscriptionTier.premium) {
      throw new Error('Realtime triggers require Premium tier');
    }

    return darkwatchScanQueue.add(
      'realtime-trigger',
      {
        subscriptionId,
        tier: subscription.tier,
        scanType: 'realtime',
        sourceData,
      },
      {
        priority: 0,
        jobId: `realtime-trigger:${subscriptionId}:${randomUUID()}`,
      }
    );
  }

  async rescheduleAll() {
    const repeatableJobs = await darkwatchScanQueue.getRepeatableJobs();

    for (const job of repeatableJobs) {
      await darkwatchScanQueue.removeRepeatableByKey(job.key);
    }

    return this.scheduleSubscriptionScans();
  }

  async getScanSchedule(subscriptionId: string) {
    const subscription = await prisma.subscription.findUnique({
      where: { id: subscriptionId },
      select: { tier: true },
    });

    if (!subscription) return null;

    const frequency = tierConfig[subscription.tier].features.darkWebScanFrequency;

    return {
      subscriptionId,
      tier: subscription.tier,
      frequency,
      cron: CRON_EXPRESSIONS[frequency],
      nextRun: frequency === 'realtime' ? 'event-driven' : CRON_EXPRESSIONS[frequency],
    };
  }
}

export const schedulerService = new SchedulerService();
