import { CampaignRepository } from "@/internal/repository/campaigns/campaigns";
import { BlockedEmailRepository } from "@/internal/repository/campaigns/blocked_emails";
import { ExternalMemberRepository } from "@/internal/repository/members/external_members";
import { logError } from "@/lib/logger";
import { CampaignService } from "@/v1/services/admin/notifications/campaign.service";
import { UpdotCoreAuthManager } from "@/lib/updot-core-auth";
import type { Kysely } from "kysely";
import { initSocket } from "@/internal/socket";
import { CampaignWorker } from "@/internal/queue/campaign.worker";
import { NotificationTargetWorker } from "@/internal/queue/notification-target.worker";
import { DefaultEmailRepository } from "@/internal/repository/campaigns/default_emails";
import { processScheduledOffers } from "@/internal/queue/scheduled-offers.worker";
import { processAccountDeletionFollowups } from "@/internal/queue/account-deletion-followup.worker";
import { purgeDeliveredExportFiles } from "@/internal/queue/export-file-purge.worker";

export async function initializeBackgroundServices(
    pool: Kysely<any>,
    memberPool: Kysely<any>,
    httpServer: any
) {
    const service = new CampaignService(
        new CampaignRepository(pool),
        new ExternalMemberRepository(memberPool),
        new BlockedEmailRepository(pool),
        new DefaultEmailRepository(pool),
    );
    try {
        const worker = new CampaignWorker(service);
        worker.start().catch(e => logError(`Failed to start Campaign Worker: ${e}`));
    } catch (e) {
        logError(`Failed to import Campaign Worker: ${e}`);
    }

    service.recoverStuckCampaigns().catch(e => logError(`Recovery error: ${e}`));

    try {
        const notifTargetWorker = new NotificationTargetWorker();
        notifTargetWorker.start();
    } catch (e) {
        logError(`Failed to start NotificationTargetWorker: ${e}`);
    }

    const runScheduler = async () => {
        try {
            await service.processScheduledCampaigns();
        } catch (e) {
            logError(`Scheduler error: ${e}`);
        } finally {
            setTimeout(runScheduler, 5 * 1000);
        }
    };
    runScheduler();

    try {
        initSocket(httpServer);
    } catch (e) {
        logError(`Failed to initialize sockets: ${e}`);
    }

    try {
        const memberAuthManager = UpdotCoreAuthManager.getInstance();
        memberAuthManager.startRotationWorker();
    } catch (e) {
        logError(`Failed to initialize UpdotCoreAuthManager worker: ${e}`);
    }

    const runScheduledOffersWorker = async () => {
        try {
            await processScheduledOffers(pool);
        } catch (e) {
            logError(`[ScheduledOffers] Scheduler error: ${e}`);
        } finally {
            setTimeout(runScheduledOffersWorker, 60 * 1000);
        }
    };
    runScheduledOffersWorker();

    /*
     * Retention sweep for delivered export workbooks.
     *
     * Hourly rather than by the minute: the window is 24 hours, so files are removed
     * between 24 and 25 hours after delivery and checking more often would only add
     * queries and bucket calls for no practical gain.
     */
    /*
     * The 30-day follow-up mail for retired accounts.
     *
     * Hourly, for the same reason as the purge below: the window is thirty days, so
     * an hour of lateness is imperceptible and a tighter loop would only add
     * queries. The sweep is a single indexed read that returns nothing on almost
     * every pass.
     */
    const runAccountDeletionFollowupWorker = async () => {
        try {
            await processAccountDeletionFollowups(pool);
        } catch (e) {
            logError(`[AccountDeletionFollowup] Scheduler error: ${e}`);
        } finally {
            setTimeout(runAccountDeletionFollowupWorker, 60 * 60 * 1000);
        }
    };
    runAccountDeletionFollowupWorker();

    const runExportFilePurgeWorker = async () => {
        try {
            await purgeDeliveredExportFiles(pool);
        } catch (e) {
            logError(`[ExportFilePurge] Scheduler error: ${e}`);
        } finally {
            setTimeout(runExportFilePurgeWorker, 60 * 60 * 1000);
        }
    };
    runExportFilePurgeWorker();
}
