import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import axios from 'axios'; import * as dayjs from 'dayjs'; import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; import { Bid } from '../entities/bid.entity'; import { Constant } from '../utils/constant'; @Injectable() export class BotTelegramApi { private readonly botToken: string; private readonly apiUrl: string; constructor(private readonly configService: ConfigService) { this.botToken = this.configService.get('TELEGRAM_BOT_TOKEN'); this.apiUrl = `https://api.telegram.org/bot${this.botToken}`; } formatBidMessage(bid: Bid) { return `πŸ“’ New Bid Alert!\n πŸ“Œ Product: ${bid.name ? `${bid.name}` : '_No name_'}\n πŸ’° Current Price: ${bid.current_price.toLocaleString()}${bid.plus_price ? ` (+${bid.plus_price.toLocaleString()})` : ''}\n πŸ† Max Price: ${bid.max_price.toLocaleString()}\n πŸ”– Starting Price: ${bid.reserve_price.toLocaleString()}\n\n πŸ“¦ Model: ${bid.model || 'None'}\n πŸ”’ Quantity: ${bid.quantity}\n πŸ†” Lot ID: ${bid.lot_id ? bid.lot_id.toString() : 'None'}\n\n ⏳ Closing Time: ${bid.close_time ? `${dayjs(bid.close_time).format('HH:mm:ss DD/MM/YYYY')}` : '_Not available_'}\n πŸš€ Start Time: ${bid.start_bid_time ? `${dayjs(bid.start_bid_time).format('HH:mm:ss DD/MM/YYYY')}` : '_Not available_'}\n\n πŸ“ˆ Bid History:\n${ bid.histories.length > 0 ? bid.histories .map( (h, index) => ` ${index + 1}. πŸ’΅ ${index === 0 ? 'πŸ”΄' : ''}${h.price.toLocaleString()} πŸ•’ ${dayjs(h.updated_at).format('HH:mm:ss DD/MM/YYYY')}`, ) .join('\n') : '_No bid history yet_' }\n\n πŸ“ Status: ${bid.status.replace('-', ' ')}\n\n ⬇️ View Details: Click here`; } async sendMessage( text: string, bonusBody: Record = {}, chatId: string = this.configService.get('CHAT_ID'), ): Promise { try { const url = `${this.apiUrl}/sendMessage`; const response = await axios.post( url, { chat_id: chatId, text: text, ...bonusBody, }, { family: 4, }, ); } catch (error) { console.error('Error sending message:', error || error.message); } } async createFolderPath(): Promise { const rootDir = process.cwd(); const folderPath = join(rootDir, `${Constant.BOT_TELEGRAM_PATH}`); if (!existsSync(folderPath)) { mkdirSync(folderPath, { recursive: true, mode: 0o777 }); // βœ… LΖ°u metadata lαΊ§n Δ‘αΊ§u const metadataPath = join(folderPath, 'metadata.json'); writeFileSync( metadataPath, JSON.stringify({ createdAt: Date.now() }), 'utf-8', ); } return folderPath; } async getGroupInfo( chatId: string = this.configService.get('CHAT_ID'), ): Promise { try { const folderPath = await this.createFolderPath(); const metadataPath = join(folderPath, 'metadata.json'); const dataFilePath = join(folderPath, `group_${chatId}.json`); // 10 minute const TIME_TO_REFRESH_DATA = 10; if (existsSync(metadataPath)) { const metadata = JSON.parse(readFileSync(metadataPath, 'utf-8')); const createdAt = metadata?.createdAt || 0; const now = Date.now(); const diffMinutes = (now - createdAt) / 60000; if (diffMinutes < TIME_TO_REFRESH_DATA && existsSync(dataFilePath)) { return JSON.parse(readFileSync(dataFilePath, 'utf-8')); } } const url = `${this.apiUrl}/getChat`; const { data } = await axios({ url, params: { chat_id: chatId }, family: 4, }); if (data?.ok) { writeFileSync( dataFilePath, JSON.stringify(data.result, null, 2), 'utf-8', ); writeFileSync( metadataPath, JSON.stringify({ createdAt: Date.now() }), 'utf-8', ); return data.result; } } catch (error) { console.error(error || error.message); } } async sendBidInfo(bid: Bid): Promise { try { const text = this.formatBidMessage(bid); await this.sendMessage(text, { parse_mode: 'HTML', }); return true; } catch (error) { console.log('SEND MESSAGE FAILURE'); return false; } } }