/*
 * Copyright (C) 2026 Fluxer Contributors
 *
 * This file is part of Fluxer.
 *
 * Fluxer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Fluxer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
 */

import {AdminRepository} from '@fluxer/api/src/admin/AdminRepository';
import {AdminArchiveRepository} from '@fluxer/api/src/admin/repositories/AdminArchiveRepository';
import {SystemDmJobRepository} from '@fluxer/api/src/admin/repositories/SystemDmJobRepository';
import {Config} from '@fluxer/api/src/Config';
import {ChannelRepository} from '@fluxer/api/src/channel/ChannelRepository';
import {ChannelService} from '@fluxer/api/src/channel/services/ChannelService';
import {ConnectionRepository} from '@fluxer/api/src/connection/ConnectionRepository';
import {ConnectionService} from '@fluxer/api/src/connection/ConnectionService';
import {CsamEvidenceRetentionService} from '@fluxer/api/src/csam/CsamEvidenceRetentionService';
import {CsamScanJobService} from '@fluxer/api/src/csam/CsamScanJobService';
import {createEmailProvider} from '@fluxer/api/src/email/EmailProviderFactory';
import {FavoriteMemeRepository} from '@fluxer/api/src/favorite_meme/FavoriteMemeRepository';
import {GuildAuditLogService} from '@fluxer/api/src/guild/GuildAuditLogService';
import {GuildRepository} from '@fluxer/api/src/guild/repositories/GuildRepository';
import {ExpressionAssetPurger} from '@fluxer/api/src/guild/services/content/ExpressionAssetPurger';
import {GuildService} from '@fluxer/api/src/guild/services/GuildService';
import {AssetDeletionQueue} from '@fluxer/api/src/infrastructure/AssetDeletionQueue';
import {AvatarService} from '@fluxer/api/src/infrastructure/AvatarService';
import {CloudflarePurgeQueue, NoopPurgeQueue} from '@fluxer/api/src/infrastructure/CloudflarePurgeQueue';
import {DisabledLiveKitService} from '@fluxer/api/src/infrastructure/DisabledLiveKitService';
import {DiscriminatorService} from '@fluxer/api/src/infrastructure/DiscriminatorService';
import {EmbedService} from '@fluxer/api/src/infrastructure/EmbedService';
import {EntityAssetService} from '@fluxer/api/src/infrastructure/EntityAssetService';
import type {IGatewayService} from '@fluxer/api/src/infrastructure/IGatewayService';
import type {ILiveKitService} from '@fluxer/api/src/infrastructure/ILiveKitService';
import type {IMediaService} from '@fluxer/api/src/infrastructure/IMediaService';
import {InMemoryVoiceRoomStore} from '@fluxer/api/src/infrastructure/InMemoryVoiceRoomStore';
import type {IStorageService} from '@fluxer/api/src/infrastructure/IStorageService';
import type {IVoiceRoomStore} from '@fluxer/api/src/infrastructure/IVoiceRoomStore';
import {KVAccountDeletionQueueService} from '@fluxer/api/src/infrastructure/KVAccountDeletionQueueService';
import {KVActivityTracker} from '@fluxer/api/src/infrastructure/KVActivityTracker';
import {KVBulkMessageDeletionQueueService} from '@fluxer/api/src/infrastructure/KVBulkMessageDeletionQueueService';
import {LiveKitService} from '@fluxer/api/src/infrastructure/LiveKitService';
import type {SnowflakeService} from '@fluxer/api/src/infrastructure/SnowflakeService';
import {createStorageService} from '@fluxer/api/src/infrastructure/StorageServiceFactory';
import {UnfurlerService} from '@fluxer/api/src/infrastructure/UnfurlerService';
import {UserCacheService} from '@fluxer/api/src/infrastructure/UserCacheService';
import {VirusScanService} from '@fluxer/api/src/infrastructure/VirusScanService';
import {VoiceRoomStore} from '@fluxer/api/src/infrastructure/VoiceRoomStore';
import {InstanceConfigRepository} from '@fluxer/api/src/instance/InstanceConfigRepository';
import {InviteRepository} from '@fluxer/api/src/invite/InviteRepository';
import {InviteService} from '@fluxer/api/src/invite/InviteService';
import {Logger} from '@fluxer/api/src/Logger';
import {LimitConfigService} from '@fluxer/api/src/limits/LimitConfigService';
import {
	getGatewayService,
	getInjectedS3Service,
	getKVClient,
	getMediaService,
	getWorkerService,
} from '@fluxer/api/src/middleware/ServiceRegistry';
import {ApplicationRepository} from '@fluxer/api/src/oauth/repositories/ApplicationRepository';
import {OAuth2TokenRepository} from '@fluxer/api/src/oauth/repositories/OAuth2TokenRepository';
import {PackRepository} from '@fluxer/api/src/pack/PackRepository';
import {PackService} from '@fluxer/api/src/pack/PackService';
import {ReadStateRepository} from '@fluxer/api/src/read_state/ReadStateRepository';
import {ReadStateService} from '@fluxer/api/src/read_state/ReadStateService';
import {ReportRepository} from '@fluxer/api/src/report/ReportRepository';
import {PaymentRepository} from '@fluxer/api/src/user/repositories/PaymentRepository';
import {UserContactChangeLogRepository} from '@fluxer/api/src/user/repositories/UserContactChangeLogRepository';
import {UserRepository} from '@fluxer/api/src/user/repositories/UserRepository';
import {UserContactChangeLogService} from '@fluxer/api/src/user/services/UserContactChangeLogService';
import {UserDeletionEligibilityService} from '@fluxer/api/src/user/services/UserDeletionEligibilityService';
import {UserHarvestRepository} from '@fluxer/api/src/user/UserHarvestRepository';
import {UserPermissionUtils} from '@fluxer/api/src/utils/UserPermissionUtils';
import {VoiceRepository} from '@fluxer/api/src/voice/VoiceRepository';
import {VoiceTopology} from '@fluxer/api/src/voice/VoiceTopology';
import {WebhookRepository} from '@fluxer/api/src/webhook/WebhookRepository';
import {KVCacheProvider} from '@fluxer/cache/src/providers/KVCacheProvider';
import {EmailI18nService} from '@fluxer/email/src/EmailI18nService';
import type {EmailConfig, UserBouncedEmailChecker} from '@fluxer/email/src/EmailProviderTypes';
import {EmailService} from '@fluxer/email/src/EmailService';
import type {IEmailService} from '@fluxer/email/src/IEmailService';
import {TestEmailService} from '@fluxer/email/src/TestEmailService';
import type {IKVProvider} from '@fluxer/kv_client/src/IKVProvider';
import {RateLimitService} from '@fluxer/rate_limit/src/RateLimitService';
import type {IWorkerService} from '@fluxer/worker/src/contracts/IWorkerService';
import Stripe from 'stripe';

let _workerTestEmailService: TestEmailService | null = null;
function getWorkerTestEmailService(): TestEmailService {
	if (!_workerTestEmailService) {
		_workerTestEmailService = new TestEmailService();
	}
	return _workerTestEmailService;
}

export interface WorkerDependencies {
	kvClient: IKVProvider;
	snowflakeService: SnowflakeService;
	limitConfigService: LimitConfigService;

	userRepository: UserRepository;
	channelRepository: ChannelRepository;
	guildRepository: GuildRepository;
	favoriteMemeRepository: FavoriteMemeRepository;
	applicationRepository: ApplicationRepository;
	oauth2TokenRepository: OAuth2TokenRepository;
	readStateRepository: ReadStateRepository;
	adminRepository: AdminRepository;
	reportRepository: ReportRepository;
	paymentRepository: PaymentRepository;
	userHarvestRepository: UserHarvestRepository;
	adminArchiveRepository: AdminArchiveRepository;
	systemDmJobRepository: SystemDmJobRepository;
	voiceRepository: VoiceRepository | null;
	connectionRepository: ConnectionRepository;
	connectionService: ConnectionService;

	cacheService: KVCacheProvider;
	userCacheService: UserCacheService;
	storageService: IStorageService;
	assetDeletionQueue: AssetDeletionQueue;
	purgeQueue: CloudflarePurgeQueue | NoopPurgeQueue;

	gatewayService: IGatewayService;
	mediaService: IMediaService;
	discriminatorService: DiscriminatorService;
	avatarService: AvatarService;
	virusScanService: VirusScanService;
	rateLimitService: RateLimitService;
	emailService: IEmailService;
	inviteService: InviteService;

	workerService: IWorkerService;
	unfurlerService: UnfurlerService;
	embedService: EmbedService;
	readStateService: ReadStateService;
	userPermissionUtils: UserPermissionUtils;
	activityTracker: KVActivityTracker;
	deletionQueueService: KVAccountDeletionQueueService;
	bulkMessageDeletionQueueService: KVBulkMessageDeletionQueueService;
	deletionEligibilityService: UserDeletionEligibilityService;

	voiceRoomStore: IVoiceRoomStore;
	liveKitService: ILiveKitService;
	voiceTopology: VoiceTopology | null;

	channelService: ChannelService;
	guildAuditLogService: GuildAuditLogService;
	contactChangeLogService: UserContactChangeLogService;
	csamEvidenceRetentionService: CsamEvidenceRetentionService;

	stripe: Stripe | null;
	csamScanJobService: CsamScanJobService;
}

export async function initializeWorkerDependencies(snowflakeService: SnowflakeService): Promise<WorkerDependencies> {
	Logger.info('Initializing worker dependencies...');

	const kvClient = getKVClient();

	const userRepository = new UserRepository();
	const channelRepository = new ChannelRepository();
	const guildRepository = new GuildRepository();
	const favoriteMemeRepository = new FavoriteMemeRepository();
	const applicationRepository = new ApplicationRepository();
	const oauth2TokenRepository = new OAuth2TokenRepository();
	const readStateRepository = new ReadStateRepository();
	const adminRepository = new AdminRepository();
	const adminArchiveRepository = new AdminArchiveRepository();
	const systemDmJobRepository = new SystemDmJobRepository();
	const reportRepository = new ReportRepository();
	const paymentRepository = new PaymentRepository();
	const userHarvestRepository = new UserHarvestRepository();
	const contactChangeLogRepository = new UserContactChangeLogRepository();
	const contactChangeLogService = new UserContactChangeLogService(contactChangeLogRepository);
	const connectionRepository = new ConnectionRepository();

	const cacheService = new KVCacheProvider({client: kvClient});
	const instanceConfigRepository = new InstanceConfigRepository();
	const limitConfigSubscriber = getKVClient();
	const limitConfigService = new LimitConfigService(instanceConfigRepository, cacheService, limitConfigSubscriber);
	await limitConfigService.initialize();
	const userCacheService = new UserCacheService(cacheService, userRepository);
	const storageService = createStorageService({s3Service: getInjectedS3Service()});
	const csamEvidenceRetentionService = new CsamEvidenceRetentionService(storageService);
	const assetDeletionQueue = new AssetDeletionQueue(kvClient);
	const purgeQueue = Config.cloudflare.purgeEnabled ? new CloudflarePurgeQueue(kvClient) : new NoopPurgeQueue();

	const gatewayService = getGatewayService();
	const connectionService = new ConnectionService(connectionRepository, gatewayService, null);
	const mediaService = getMediaService();
	const discriminatorService = new DiscriminatorService(userRepository, cacheService, limitConfigService);
	const avatarService = new AvatarService(storageService, mediaService, limitConfigService);
	const entityAssetService = new EntityAssetService(
		storageService,
		mediaService,
		assetDeletionQueue,
		limitConfigService,
	);
	const virusScanService = new VirusScanService(cacheService);
	const rateLimitService = new RateLimitService(cacheService);
	const packRepository = new PackRepository();
	const packAssetPurger = new ExpressionAssetPurger(assetDeletionQueue);
	const packService = new PackService(
		packRepository,
		guildRepository,
		avatarService,
		snowflakeService,
		packAssetPurger,
		userRepository,
		userCacheService,
		limitConfigService,
	);
	const emailConfig: EmailConfig = {
		enabled: Config.email.enabled,
		fromEmail: Config.email.fromEmail,
		fromName: Config.email.fromName,
		appBaseUrl: Config.endpoints.webApp,
		marketingBaseUrl: Config.endpoints.marketing,
	};

	const bouncedEmailChecker: UserBouncedEmailChecker = {
		isEmailBounced: async (email: string) => {
			const user = await userRepository.findByEmail(email);
			return user?.emailBounced ?? false;
		},
	};

	const emailI18n = new EmailI18nService();
	const emailProvider = createEmailProvider(Config.email);
	const emailService: IEmailService = Config.dev.testModeEnabled
		? getWorkerTestEmailService()
		: new EmailService(emailConfig, emailI18n, emailProvider, bouncedEmailChecker);

	const workerService = getWorkerService();
	const guildAuditLogService = new GuildAuditLogService(guildRepository, snowflakeService, workerService);
	const unfurlerService = new UnfurlerService(cacheService, mediaService);
	const embedService = new EmbedService(channelRepository, cacheService, unfurlerService, mediaService, workerService);
	const readStateService = new ReadStateService(readStateRepository, gatewayService);
	const userPermissionUtils = new UserPermissionUtils(userRepository, guildRepository);
	const activityTracker = new KVActivityTracker(kvClient);
	const deletionQueueService = new KVAccountDeletionQueueService(kvClient, userRepository);
	const bulkMessageDeletionQueueService = new KVBulkMessageDeletionQueueService(kvClient);
	const deletionEligibilityService = new UserDeletionEligibilityService(kvClient);
	const csamScanJobService = new CsamScanJobService();

	let voiceRepository: VoiceRepository | null = null;
	let voiceTopology: VoiceTopology | null = null;
	let voiceRoomStore: IVoiceRoomStore;
	let liveKitService: ILiveKitService;

	if (Config.voice.enabled) {
		voiceRepository = new VoiceRepository();
		voiceTopology = new VoiceTopology(voiceRepository, null);
		await voiceTopology.initialize();
		voiceRoomStore = new VoiceRoomStore(kvClient);
		liveKitService = new LiveKitService(voiceTopology);
		Logger.info('Voice services initialized');
	} else {
		voiceRoomStore = new InMemoryVoiceRoomStore();
		liveKitService = new DisabledLiveKitService();
	}

	const inviteRepository = new InviteRepository();
	const webhookRepository = new WebhookRepository();

	const channelService = new ChannelService(
		channelRepository,
		userRepository,
		guildRepository,
		packService,
		userCacheService,
		embedService,
		readStateService,
		cacheService,
		storageService,
		gatewayService,
		mediaService,
		avatarService,
		workerService,
		virusScanService,
		snowflakeService,
		rateLimitService,
		purgeQueue,
		favoriteMemeRepository,
		guildAuditLogService,
		voiceRoomStore,
		liveKitService,
		inviteRepository,
		webhookRepository,
		limitConfigService,
		undefined,
	);
	const guildService = new GuildService(
		guildRepository,
		channelRepository,
		inviteRepository,
		channelService,
		userCacheService,
		gatewayService,
		entityAssetService,
		avatarService,
		assetDeletionQueue,
		userRepository,
		mediaService,
		cacheService,
		snowflakeService,
		rateLimitService,
		workerService,
		webhookRepository,
		guildAuditLogService,
		limitConfigService,
		undefined,
	);
	const inviteService = new InviteService(
		inviteRepository,
		guildService,
		channelService,
		gatewayService,
		guildAuditLogService,
		userRepository,
		packRepository,
		packService,
		limitConfigService,
	);

	let stripe: Stripe | null = null;
	if (Config.stripe.enabled && Config.stripe.secretKey) {
		stripe = new Stripe(Config.stripe.secretKey, {
			apiVersion: '2026-01-28.clover',
			httpClient: Config.dev.testModeEnabled ? Stripe.createFetchHttpClient() : undefined,
		});
		Logger.info('Stripe initialized');
	}

	Logger.info('Worker dependencies initialized successfully');

	return {
		kvClient,
		snowflakeService,
		limitConfigService,
		userRepository,
		channelRepository,
		guildRepository,
		favoriteMemeRepository,
		applicationRepository,
		oauth2TokenRepository,
		readStateRepository,
		adminRepository,
		reportRepository,
		paymentRepository,
		userHarvestRepository,
		adminArchiveRepository,
		systemDmJobRepository,
		voiceRepository,
		connectionRepository,
		connectionService,
		cacheService,
		userCacheService,
		storageService,
		assetDeletionQueue,
		purgeQueue,
		gatewayService,
		mediaService,
		discriminatorService,
		avatarService,
		virusScanService,
		rateLimitService,
		emailService,
		inviteService,
		workerService,
		unfurlerService,
		embedService,
		readStateService,
		userPermissionUtils,
		activityTracker,
		deletionQueueService,
		bulkMessageDeletionQueueService,
		deletionEligibilityService,
		voiceRoomStore,
		liveKitService,
		voiceTopology,
		channelService,
		guildAuditLogService,
		contactChangeLogService,
		csamEvidenceRetentionService,
		stripe,
		csamScanJobService,
	};
}

export async function shutdownWorkerDependencies(_deps: WorkerDependencies): Promise<void> {
	Logger.info('Shutting down worker dependencies...');
	Logger.info('Worker dependencies shut down successfully');
}
