giveawayService.ts

1import { Client, TextChannel, EmbedBuilder } from 'discord.js'
2import { supabase } from '@/configs/supabase'
3import Logger from '@/classes/logger'
4
5export class GiveawayService {
6	private client: Client
7	private interval: NodeJS.Timeout | null = null
8
9	constructor(client: Client) {
10		this.client = client
11	}
12
13	start() {
14		// Check for ended giveaways every minute
15		this.interval = setInterval(() => this.checkGiveaways(), 60000)
16		Logger.log('info', 'Giveaway service started', 'GiveawayService')
17	}
18
19	async checkGiveaways() {
20		const { data: giveaways, error } = await supabase
21			.from('giveaways')
22			.select('*')
23			.eq('ended', false)
24			.lte('ends_at', new Date().toISOString())
25
26		if (error) {
27			Logger.log(
28				'error',
29				`Failed to fetch giveaways: ${error.message}`,
30				'GiveawayService',
31			)
32			return
33		}
34
35		for (const giveaway of giveaways) {
36			try {
37				const channel = (await this.client.channels.fetch(
38					giveaway.channel_id,
39				)) as TextChannel
40				const message = await channel.messages.fetch(giveaway.message_id)
41
42				const reaction = message.reactions.cache.get('🎉')
43				if (!reaction) throw new Error('Reaction not found')
44
45				const users = await reaction.users.fetch()
46				const validParticipants = users.filter((user) => !user.bot)
47
48				if (validParticipants.size < 1) {
49					await channel.send(
50						`No valid participants for giveaway: ${giveaway.prize}`,
51					)
52					continue
53				}
54
55				const winners = validParticipants.random(
56					Math.min(giveaway.winner_count, validParticipants.size),
57				)
58
59				const winnerAnnouncement = new EmbedBuilder()
60					.setTitle('🎉 Giveaway Ended! 🎉')
61					.setDescription(
62						`
63            **Prize:** ${giveaway.prize}
64            **Winners:** ${winners.map((w) => `<@${w.id}>`).join(', ')}
65          `,
66					)
67					.setColor('#00FF00')
68					.setFooter({ text: `Giveaway ID: ${giveaway.message_id}` })
69
70				await channel.send({ embeds: [winnerAnnouncement] })
71
72				// Update giveaway as ended
73				await supabase
74					.from('giveaways')
75					.update({ ended: true })
76					.eq('message_id', giveaway.message_id)
77			} catch (error: any) {
78				Logger.log(
79					'error',
80					`Failed to end giveaway: ${error.message}`,
81					'GiveawayService',
82				)
83			}
84		}
85	}
86
87	stop() {
88		if (this.interval) {
89			clearInterval(this.interval)
90			this.interval = null
91			Logger.log('info', 'Giveaway service stopped', 'GiveawayService')
92		}
93	}
94}
95