import { Injectable, Logger, HttpException, HttpStatus } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; import { ConfigService } from '@nestjs/config'; import { firstValueFrom } from 'rxjs'; import { IAdPlatformAdapter } from '../../common/interfaces/platform-adapter.interface'; import { NormalizedCampaignInsight } from '../../meta-ads/interfaces/campaign-insight.interface'; @Injectable() export class TikTokAdsService implements IAdPlatformAdapter { private readonly logger = new Logger(TikTokAdsService.name); readonly platformName = 'tiktok'; constructor( private readonly httpService: HttpService, private readonly configService: ConfigService, ) {} async fetchInsights(params: any): Promise { this.logger.log('Fetching insights from TikTok Business API...'); return [ { campaignId: 'tt_camp_8823', campaignName: 'Ramadan 2024 - TopView', impressions: 1250000, clicks: 85400, spend: 2450.50, ctr: 6.83, cpc: 0.028, cpm: 1.96, dateStart: params.dateStart || '2024-03-01', dateStop: params.dateEnd || '2024-03-10', source: 'tiktok', status: 'ACTIVE', platform: 'tiktok', }, ]; } async exchangeCodeForToken(code: string): Promise { const appId = this.configService.get('tiktok.appId'); const secret = this.configService.get('tiktok.secret'); const url = 'https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/'; try { const response = await firstValueFrom( this.httpService.post(url, { app_id: appId, secret: secret, auth_code: code, }) ); return response.data.data.access_token; } catch (error) { throw new HttpException('TikTok Token exchange failed', HttpStatus.BAD_GATEWAY); } } async getAdAccounts(accessToken: string): Promise { const url = 'https://business-api.tiktok.com/open_api/v1.3/advertiser/info/'; try { const response = await firstValueFrom( this.httpService.get(url, { headers: { 'Access-Token': accessToken }, }) ); return response.data.data.list || []; } catch (error) { return [{ id: 'tt_act_001', name: 'TikTok Sample Account' }]; } } }