import { Injectable, HttpException, HttpStatus, OnModuleInit } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import axios from 'axios';
import { log } from 'console';
const moment = require('moment');
import { env, title } from 'process';
import { uploadFileToS3 } from 'src/common/config/upload-s3-file-using-link';
import { Constants } from 'src/common/constants';
import { KeyType, Settings } from 'src/entities/settings.entity';
import { SocialMediaPosts } from 'src/entities/social-media-posts.entity';
import { SocialMedias, SocialType } from 'src/entities/social-medias.entity';
import { Users } from 'src/entities/users.entity';
import { YoutubeChannels } from 'src/entities/youtube-channel.entity';
import { YoutubeVideos } from 'src/entities/youtube-videos.entity';
import { responseMessages } from 'src/messages/response-messages';
import { IsNull, Not, Repository } from 'typeorm';
import { EncryptionService } from '../encryption/encryption.service';
import { access } from 'fs';
import { CounterService } from 'src/common/config/counter.service';

@Injectable()
export class YoutubeServices implements OnModuleInit {
    public YOUTUBE_API_KEY = "";
    public s3Config = {};
    constructor(
        private encryptionService: EncryptionService,
        @InjectRepository(Users)
        private Users: Repository<Users>,

        @InjectRepository(SocialMedias)
        private SocialMedias: Repository<SocialMedias>,

        @InjectRepository(YoutubeChannels)
        private YoutubeChannels: Repository<YoutubeChannels>,

        @InjectRepository(YoutubeVideos)
        private YoutubeVideos: Repository<YoutubeVideos>,

        @InjectRepository(Settings)
        private Settings: Repository<Settings>,

        @InjectRepository(SocialMediaPosts)
        private SocialMediaPosts: Repository<SocialMediaPosts>,

    ) { }

    async onModuleInit() {
        this.YOUTUBE_API_KEY = await this.encryptionService.decrypt(process.env.YOUTUBE_API_KEY);
        this.s3Config = {
            accessKeyId: await this.encryptionService.decrypt(process.env.AWS_ACCESS_KEY_ID),
            secretAccessKey: await this.encryptionService.decrypt(process.env.AWS_SECRET_ACCESS_KEY),
            region: process.env.AWS_DEFAULT_REGION,
        }
    }
    async sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    /**
     * Integrates a YouTube account with the application by fetching and saving the user's channel data.
     *
     * @param request - The request object containing the access token for YouTube API authentication.
     * @param authUser - The authenticated user object associated with the YouTube account.
     * 
     * @returns A promise that resolves to true if the integration is successful.
     * 
     * @throws HttpException - Throws a 400 error if the YouTube channel does not exist.
     * @throws HttpException - Throws a 206 error if the YouTube account is not eligible for linking.
     * @throws HttpException - Throws an error with the original error message and status if any other error occurs.
     * 
     * This function fetches the channel list of the authenticated user, saves the social media account,
     * checks eligibility based on subscriber count, and saves channel data. If the account is not eligible,
     * it unlinks the YouTube account. It also updates the user's total followers and the social media's 
     * follower and post counts.
     */
    async youtube(request: any, authUser: any) {
        try {
            const channelUrl = `${process.env.YOUTUBE_BASE_URL}channels`;
            const headers = {
                Authorization: `Bearer ${request.access_token}`,
            };
            const params = {
                part: 'snippet,contentDetails,statistics,contentOwnerDetails,localizations,status',
                mine: true,
            };
            let isEligible = 0;
            let socialMedia = null;
            let total_followers = 0;
            let post_count = 0;
            let about_me = null;
            let profile_image = null;
            let s3Response = null;
            // GET THE CHANNEL LIST
            const channelResponse = await this.getAxios(channelUrl, headers, params);
            if (channelResponse && channelResponse.items.length) {

                const setting = await this.Settings.findOne({ where: { type: KeyType.YOUTUBE_SUBSCRIBER_COUNT } });

                socialMedia = await this.saveSocialMedia(request, authUser);
                if (socialMedia) {
                    for (const channel of channelResponse.items) {
                        // SAVE SOCIAL MEDIA ACCOUNT 
                        profile_image = channel['snippet']['thumbnails']['medium']['url'];
                        s3Response = await uploadFileToS3(profile_image, `images/profile/`, this.s3Config);
                        // CHECK THE PLATFORM LINK ELIGIBILITY 
                        if (channel['statistics']['subscriberCount'] >= parseInt(setting.value)) {
                            isEligible = 1;
                            const youtubeChannel = {
                                users: authUser,
                                socialMedia: socialMedia,
                                title: channel['snippet']['title'],
                                description: channel['snippet']['description'],
                                channel_name: channel['snippet']['customUrl'],
                                published_at: moment(channel['snippet']['publishedAt']).format('YYYY-MM-DD HH:mm:ss'),
                                thumbnails: s3Response?.path || channel['snippet']['thumbnails']['medium']['url'],
                                localized: JSON.stringify(channel['snippet']['localized']),
                                content_id: channel['contentDetails']['relatedPlaylists']['uploads'],
                                view_counts: channel['statistics']['viewCount'],
                                subscriber_count: channel['statistics']['subscriberCount'],
                                video_count: channel['statistics']['videoCount'],
                                url: 'https://www.youtube.com/' + channel['snippet']['customUrl'],
                            }
                            about_me = channel['snippet']['description'];

                            total_followers += channel['statistics']['subscriberCount'];
                            post_count += channel['statistics']['videoCount'];
                            // SAVE CHANNEL DATA
                            const saveChannel = await this.YoutubeChannels.save(youtubeChannel);
                            if (saveChannel) {
                                await this.getPlayList(saveChannel, request);
                            }
                        }
                    }
                }
            } else {
                throw new HttpException(responseMessages.en.user.social_media.youtube_channel_not_exists, HttpStatus.BAD_REQUEST);
            }
            if (!isEligible) {
                this.unlinkYoutube(socialMedia)
                throw new HttpException(responseMessages.en.user.social_media.not_eligible, HttpStatus.PARTIAL_CONTENT);
            }
            //authUser['total_followers'] = Number(authUser['total_followers']) + Number(total_followers);
            if (!authUser.is_profile_pic_updated) {
                if (s3Response) {
                    authUser['image'] = s3Response.path
                } else {
                    authUser['image'] = profile_image;
                }
            }

            authUser['about_me'] = authUser['about_me'] ? authUser['about_me'] : about_me;
            if (!authUser['platforms']) {
                authUser['platforms'] = [];
            }
            if (!authUser['platforms'].includes('youtube')) {
                authUser['platforms'].push('youtube');
            }
            await this.Users.save(authUser);

            socialMedia = await this.SocialMedias.findOne({ where: { id: socialMedia.id } });
            socialMedia['follower_count'] = Number(total_followers);
            socialMedia['post_count'] = Number(post_count);
            this.SocialMedias.save(socialMedia);

            return true;
        } catch (error) {
            throw new HttpException(error.message, error.status);
        }
    }

    /**
     * Retrieves the list of videos of a YouTube channel. 
     * This API will return the list of videos in the specified playlist.
     * @param social_media - The social media profile object containing the access token.
     * @returns A promise that resolves to the list of videos.
     * @throws A HttpException if an error occurs.
     */
    async getLivePlayList(social_media, nextPageToken = null) {
        let videoArr = [];
        try {

            const playlistUrl = `${process.env.YOUTUBE_BASE_URL}playlistItems?key=${this.YOUTUBE_API_KEY}`;

            const { content_id } = await this.YoutubeChannels.findOne({ where: { socialMedia: { id: social_media.id } } });
            const params = {
                part: 'snippet',
                playlistId: content_id,
                pageToken: nextPageToken,
                maxResults: Constants.POST_LIMIT,
            };

            let playListResponse: any = await this.getAxios(playlistUrl, null, params);

            if (playListResponse && playListResponse.items.length) {
                for (const video of playListResponse.items) {
                    const videoUrl = `${process.env.YOUTUBE_BASE_URL}videos?key=${this.YOUTUBE_API_KEY}`;
                    const videoParams = {
                        part: 'snippet,contentDetails,statistics',
                        id: video['snippet']['resourceId']['videoId'],
                    };
                    let videoResponse = await this.getAxios(videoUrl, null, videoParams)
                    for (const videoInfo of videoResponse.items) {
                        videoArr.push(videoInfo)
                    }
                }
            }
            return { data: videoArr, nextPageToken: playListResponse?.nextPageToken || null };
        } catch (error) {
            return { data: [], nextPageToken: null };
        }
    }

    async getSingleVideo(videoId) {
        const videoUrl = `${process.env.YOUTUBE_BASE_URL}videos?key=${this.YOUTUBE_API_KEY}`;
        const videoParams = {
            part: 'snippet,contentDetails,statistics',
            id: videoId,
        };
        const response = await this.getAxios(videoUrl, null, videoParams)
        if (response) {
            return response?.items?.[0];
        }
        return false;
    }

    async getYoutubeVideoLink(link, user) {
        try {
            const videoId = link.split('/').pop().split('?')[0];
            const youtubePost = await this.YoutubeVideos.findOne({ where: { video_id: videoId, users: { id: user.id } } });
            if (youtubePost) {
                const videoUrl = `${process.env.YOUTUBE_BASE_URL}videos?key=${this.YOUTUBE_API_KEY}`;
                const videoParams = {
                    part: 'snippet,contentDetails,statistics',
                    id: videoId,
                };
                return await this.getAxios(videoUrl, null, videoParams)
            }
            return false;
        } catch (error) {
            console.log(error)
            return false;
        }
    }

    /**
     * Get the list of videos of a youtube channel.
     * Save the videos in the database.
     * Get the details of each video.
     * @param channel The youtube channel entity of the user.
     * @param request The request object with access token.
     * @returns A boolean indicating whether the operation was successful.
     * @throws A HttpException if an error occurs.
     */
    async getPlayList(channel, request) {

        const playlistUrl = `${process.env.YOUTUBE_BASE_URL}playlistItems`;
        const headers = {
            Authorization: `Bearer ${request.access_token}`,
        };
        let nextPageToken = null;

        //do {
        const params = {
            part: 'snippet',
            playlistId: channel.content_id,
            pageToken: nextPageToken,
            maxResults: Constants.POST_LIMIT,
        };
        // GET THE CHANNEL LIST
        const playListResponse = await this.getAxios(playlistUrl, headers, params);
        if (playListResponse && playListResponse.items.length) {
            let totalLikes: bigint = BigInt(0);
            let totalComments: bigint = BigInt(0);
            let totalViews: bigint = BigInt(0);
            let postCount = 0;
            for (const video of playListResponse.items) {
                if (postCount >= 12) {
                    break; // Limit to 12 videos
                }
                const videoUrl = `${process.env.YOUTUBE_BASE_URL}videos`;
                const videoParams = {
                    part: 'snippet,contentDetails,statistics',
                    id: video['snippet']['resourceId']['videoId'],
                };
                let videoResponse = await this.getAxios(videoUrl, headers, videoParams)
                if (videoResponse && videoResponse.items.length) {
                    for (const videoInfo of videoResponse.items) {

                        totalLikes += BigInt(videoInfo.statistics.likeCount || 0);
                        totalComments += BigInt(videoInfo.statistics.commentCount || 0);
                        totalViews += BigInt(videoInfo.statistics.viewCount || 0);
                        postCount += 1;
                        const youtubeVideo = {
                            users: channel.users,
                            socialMedia: channel.socialMedia,
                            youtubeChannel: channel,
                            title: videoInfo['snippet']['title'],
                            description: videoInfo['snippet']['description'],
                            channel_name: videoInfo['snippet']['channelTitle'],
                            published_at: moment(videoInfo['snippet']['publishedAt']).format('YYYY-MM-DD HH:mm:ss'),
                            thumbnails: videoInfo['snippet']['thumbnails']['medium']['url'],
                            localized: JSON.stringify(videoInfo['snippet']['localized']),
                            video_id: videoInfo['id'],
                            youtube_category_id: videoInfo['snippet']['categoryId'],
                            view_counts: videoInfo['statistics']['viewCount'],
                            like_count: videoInfo['statistics']['likeCount'],
                            comment_count: videoInfo['statistics']['commentCount'],
                            favorite_count: videoInfo['statistics']['favoriteCount'],
                            post_url: `https://www.youtube.com/watch?v=${videoInfo['id']}`,
                        }
                        await this.YoutubeVideos.save(youtubeVideo);

                        const socialMediaPost = {
                            users: channel.users,
                            socialMedia: channel.socialMedia,
                            title: videoInfo['snippet']['title'],
                            description: videoInfo['snippet']['description'],
                            like_count: videoInfo['statistics']['likeCount'],
                            comment_count: videoInfo['statistics']['commentCount'],
                            post_id: videoInfo['id'],
                            post_url: `https://www.youtube.com/watch?v=${videoInfo['id']}`,
                            image_url: videoInfo['snippet']['thumbnails']['medium']['url'],
                            social_type: SocialType.YOUTUBE,
                            created_time: moment(videoInfo['snippet']['publishedAt']).format('YYYY-MM-DD HH:mm:ss'),
                        }
                        this.SocialMediaPosts.save(socialMediaPost);
                    }
                }
            }
            if (totalViews) {
                const engagementRate = parseFloat(
                    (((Number(totalLikes) + Number(totalComments)) / Number(totalViews)) * 100).toFixed(4)
                );
                await this.updateSocialMediaEngagementRate(channel.socialMedia.id, engagementRate);
            }
        }
        // Update nextPageToken for pagination
        nextPageToken = playListResponse.nextPageToken;
        // } while(!nextPageToken); // Continue if there's a nextPageToken
    }

    /**
     * Saves a social media account to the user's profile.
     * 
     * @param request - An instance of SocialMediasDto containing the social media account's id and type.
     * @param authUser - The authenticated user object performing the link action.
     * 
     * @throws HttpException - Throws a 404 error if the user does not exist.
     * @throws HttpException - Throws a 400 error if the social media account already exists.
     * @throws HttpException - Throws a 400 error if the social media type is invalid.
     * 
     * After linking, the user's total followers and following counts are increased accordingly.
     */
    async saveSocialMedia(request, authUser) {
        const lang = authUser.language || 'en';
        const socialMediaExists = await this.SocialMedias.findOne({
            where: {
                users: { id: Not(authUser.id), deleted_at: IsNull() },
                social_user_name: request.social_user_name,
                social_type: request.social_media_type,
                is_verified: true
            }
        })

        if (socialMediaExists) {
            throw new HttpException(responseMessages[lang].user.social_media.arealy_exists, HttpStatus.RESET_CONTENT);
        }

        const save = await this.SocialMedias.save({
            users: authUser,
            social_id: request.social_id,
            social_type: request.social_media_type,
            social_access_token: request.access_token,
            social_user_name: request.social_user_name,
            refresh_token: request.refresh_token,
            is_verified: true,
            missing_permissions: request.missing_permissions ?? []
        });
        // UNLINK UNVERIFIED SOCIAL MEDIA
        const unlinkUnverifiedSocialMedia = await this.SocialMedias.findOne({ where: { users: { id: authUser.id }, social_type: request.social_media_type, is_verified: false } })
        if (unlinkUnverifiedSocialMedia) {
            this.unlinkYoutube(unlinkUnverifiedSocialMedia);
        }
        return save;
    }

    /**
     * Unlinks a YouTube account from the user's profile.
     * 
     * @param socialMedia - The social media account object to be unlinked.
     * 
     * Deletes all related YouTube videos, profiles, social media posts and the social media account itself.
     */
    async unlinkYoutube(socialMedia) {
        await this.YoutubeVideos.softDelete({ socialMedia: { id: socialMedia.id } });
        await this.YoutubeChannels.softDelete({ socialMedia: { id: socialMedia.id } });
        await this.SocialMediaPosts.softDelete({ socialMedia: { id: socialMedia.id } });
        await this.SocialMedias.softDelete({ id: socialMedia.id });
    }

    async youtubeEdit(request, id) {

        const youtubeChannel = await this.YoutubeChannels.findOne({ where: { id: id } });
        if (!youtubeChannel) {
            throw new HttpException(responseMessages.en.user.social_media.not_exists, HttpStatus.RESET_CONTENT);
        }

        youtubeChannel['title'] = request.name || "",
            youtubeChannel['description'] = request.bio || "",
            youtubeChannel['country_name'] = request.country || "",
            youtubeChannel['city_name'] = request.city || "",
            youtubeChannel['gender'] = request.gender || "",

            this.YoutubeChannels.save(youtubeChannel);
    }

    async getChannelVideos(postId) {
        return await this.YoutubeVideos.createQueryBuilder('video')
            .distinctOn(['video.video_id'])
            .leftJoin('video.youtubeChannel', 'channel')
            .where('channel.id = :postId', { postId })
            .orderBy('video.video_id') // required by PostgreSQL
            .addOrderBy('video.published_at', 'DESC')
            .limit(12)
            .getMany();
    }


    async getChannelIdFromName() {
        const where = { where: { social_type: SocialType.YOUTUBE, social_id: "" } };
        const count = await this.SocialMedias.count(where);
        if (count) {
            const result = await this.SocialMedias.find(where);
            for await (const socialMedia of result) {
                if (CounterService.incrementBy(2)) {
                    const channelUrl = `${process.env.YOUTUBE_BASE_URL}channels?part=snippet&forHandle=${socialMedia.social_user_name}&key=${this.YOUTUBE_API_KEY}&maxResults=1`;
                    // GET THE CHANNEL INFO
                    console.log("Channel URL: ", channelUrl);
                    const channelResponse = await this.getAxios(channelUrl);
                    if (channelResponse['items'].length) {
                        socialMedia.social_id = channelResponse['items'][0]['id'] || "NOT_FOUND";
                        console.log("Social ID: ", socialMedia.social_user_name, socialMedia.social_id);
                        await this.SocialMedias.save(socialMedia);
                    }
                }
            }
            console.log(`Total Profile processed: ${CounterService.getCount()}`);
        }
    }

    async youtubeScraper(pageSize, social_user_name = null) {
        const daysAgo = moment().subtract(Constants.SOCIAL_MEDIA_CRON_DAY, 'days').toDate();
        let query = await this.SocialMedias.createQueryBuilder('sm')
            .select(['sm.id', 'sm.social_id'])
            .where('social_type = :social_type', { social_type: SocialType.YOUTUBE })
            .andWhere('social_media_not_found = false')
            .andWhere('sm.is_verified = true')
            .andWhere('(sm.updated_by_cron <= :dateLimit OR sm.updated_by_cron IS NULL)', {
                dateLimit: daysAgo
            }).andWhere('sm.social_id != \'\'');

        // UPDATE SINGLE RECORD
        if (social_user_name) {
            query.andWhere('sm.social_user_name = :social_user_name', { social_user_name })
        }

        const [result, total] = await query.take(pageSize).getManyAndCount();

        let socialIdArr = result.map(item => item.social_id)
        if (socialIdArr.length) {
            console.log(socialIdArr);
            if (CounterService.incrementBy(socialIdArr.length * 7)) {
                await this.getChannelUsingAPIKey(result);
                if (total) {
                    await this.youtubeScraper(pageSize, social_user_name);
                }
            }
            console.log(`Total Profile processed: ${CounterService.getCount()}`);
        }
    }

    async youtubeScraperCountryFilter(country: string, condition: string, days: number, from: number, to: number = 0) {
        const pageSize = 50;
        const daysAgo = moment().subtract(days, 'days').toDate();

        let query = await this.SocialMedias.createQueryBuilder('sm')
            .select(['sm.id', 'sm.social_user_name', 'sm.social_id'])
            .where('social_type = :social_type', { social_type: SocialType.YOUTUBE })
            .andWhere('(sm.updated_by_cron <= :dateLimit OR sm.updated_by_cron IS NULL)', {
                dateLimit: daysAgo
            })
            .andWhere('social_media_not_found = false')
            .andWhere('is_verified = false')
            .andWhere('country = :country', { country });


        switch (condition) {
            case "BETWEEN":
                query.andWhere('follower_count BETWEEN :from AND :to', { from, to });
                break;
            case "GREATER_THAN":
                query.andWhere('follower_count > :from', { from });
                break;
            case "LESS_THAN":
                query.andWhere('follower_count < :from', { from });
                break;
            case "EQUAL_TO":
                query.andWhere('follower_count = :from', { from });
                break;
        }

        const [result, total] = await query.orderBy('created_at', 'ASC').take(pageSize).getManyAndCount();

        let socialIdArr = result.map(item => item.social_id)
        if (socialIdArr.length) {
            console.log(socialIdArr)
            if (CounterService.incrementBy(socialIdArr.length * 7)) {
                await this.getChannelUsingAPIKey(result);
                if (total) {
                    await this.youtubeScraperCountryFilter(country, condition, days, from, to);
                }
            }
            console.log(`Total processed: ${CounterService.getCount()}`);
        }
    }

    async getChannelUsingAPIKey(socialIdArr) {
        for await (const socialObj of socialIdArr) {
            try {
                const socialId = socialObj.social_id;
                const channelUrl = `${process.env.YOUTUBE_BASE_URL}channels?part=snippet,contentDetails,statistics,contentOwnerDetails,localizations,status&id=${socialId}&key=${this.YOUTUBE_API_KEY}&maxResults=1`;
                let socialMedia = null;
                let total_followers: bigint = BigInt(0);
                let post_count: bigint = BigInt(0);
                let engagement_rate: number = 0;
                // GET THE CHANNEL LIST
                const channelResponse = await this.getAxios(channelUrl);
                socialMedia = await this.SocialMedias.findOne({ relations: ['users'], where: { id: socialObj.id } });
                //   console.log(socialMedia)
                console.log("YOUTUBE CHANNEL NAME: ", socialMedia?.social_user_name);
                if (channelResponse && channelResponse?.items?.length) {
                    if (socialMedia) {
                        for (const channelInfo of channelResponse.items) {
                            console.log(channelInfo['snippet']['title'])
                            // GET THE CHANNEL INFO
                            const s3Response = await uploadFileToS3(channelInfo['snippet']['thumbnails']['default']['url'], `images/profile/`, this.s3Config);
                            let youtubeChannel = await this.YoutubeChannels.findOne({ where: { socialMedia: { id: socialMedia.id } } });
                            youtubeChannel.title = channelInfo['snippet']['title'];
                            youtubeChannel.description = channelInfo['snippet']['description'];
                            //  youtubeChannel.channel_name = channelInfo['snippet']['customUrl'];
                            youtubeChannel.thumbnails = s3Response?.path || channelInfo['snippet']['thumbnails']['default']['url'];
                            youtubeChannel.localized = JSON.stringify(channelInfo['snippet']['localized']);
                            youtubeChannel.view_counts = channelInfo['statistics']['viewCount'];
                            youtubeChannel.subscriber_count = channelInfo['statistics']['subscriberCount'];
                            youtubeChannel.video_count = channelInfo['statistics']['videoCount'];
                            youtubeChannel.content_id = channelInfo['contentDetails']['relatedPlaylists']['uploads'];
                            total_followers += BigInt(channelInfo['statistics']['subscriberCount']);
                            post_count += BigInt(channelInfo['statistics']['videoCount']);
                            // SAVE CHANNEL DATA
                            const channelSave = await this.YoutubeChannels.save(youtubeChannel);
                            await this.getPlayListUsingAPIKey(channelSave, socialMedia);
                            if (!socialMedia.users.is_profile_pic_updated) {
                                if (s3Response) {
                                    await this.Users.update({ id: socialMedia.users.id }, { image: s3Response.path });
                                } else {
                                    await this.Users.update({ id: socialMedia.users.id }, { image: channelInfo['snippet']['thumbnails']['default']['url'] });
                                }
                            }
                        }
                    }

                    socialMedia = await this.SocialMedias.findOne({ where: { id: socialMedia.id } });

                    socialMedia['follower_count'] = Number(total_followers);
                    socialMedia['post_count'] = Number(post_count);
                    socialMedia['is_updated'] = true;
                    socialMedia['source_posts_from'] = 'youtube';
                    socialMedia['updated_by_cron'] = moment().format('YYYY-MM-DD HH:mm:ss');
                    await this.SocialMedias.save(socialMedia);
                } else {
                    this.SocialMedias.update({ id: socialMedia.id }, { source_posts_from: 'youtube', apify_data_updated_attempts: socialMedia.apify_data_updated_attempts + 1 });
                    if (socialMedia.apify_data_updated_attempts >= 3) {
                        this.SocialMedias.update({ id: socialMedia.id }, { source_posts_from: 'youtube', social_media_not_found: true, is_updated: true, updated_by_cron: moment().format('YYYY-MM-DD HH:mm:ss') });
                    }
                }
            } catch (error) {
                console.log(error);
            }
        }
    }

    async getPlayListUsingAPIKey(channel, socialMedia) {
        const playlistUrl = `${process.env.YOUTUBE_BASE_URL}playlistItems?part=snippet&playlistId=${channel.content_id}&maxResults=12&key=${this.YOUTUBE_API_KEY}`;
        //const videosUrl = `${process.env.YOUTUBE_BASE_URL}search?part=snippet&type=video&channelId=${socialMedia.social_id}&maxResults=12&order=date&key=${this.YOUTUBE_API_KEY}`;

        let nextPageToken = null;
        await this.YoutubeVideos.delete({ youtubeChannel: { id: channel.id } });
        await this.SocialMediaPosts.delete({ socialMedia: { id: socialMedia.id } });
        // GET THE CHANNEL LIST
        const playListResponse = await this.getAxios(playlistUrl);
        let postCount = 0;
        let totalLikes: bigint = BigInt(0);
        let totalComments: bigint = BigInt(0);
        let totalViews: bigint = BigInt(0);
        let videoId = [];
        if (playListResponse && playListResponse.items.length) {
            for (const video of playListResponse.items) {
                if (videoId.includes(video['snippet']['resourceId']['videoId'])) {
                    continue; // Skip if video already processed
                }
                videoId.push(video['snippet']['resourceId']['videoId']);
                if (videoId.length > 12) {
                    break; // Limit to 12 videos
                }
            }
            if (!videoId.length) {
                return false; // No videos to process
            }
            const videoUrl = `${process.env.YOUTUBE_BASE_URL}videos?part=snippet,contentDetails,statistics&id=${videoId.join(',')}&key=${this.YOUTUBE_API_KEY}`;

            let videoResponse = await this.getAxios(videoUrl)
            if (videoResponse && videoResponse.items.length) {
                for (const videoInfo of videoResponse.items) {

                    console.log("Video Count: ", postCount, videoInfo['snippet']['title'])
                    totalLikes += BigInt(videoInfo.statistics.likeCount || 0);
                    totalComments += BigInt(videoInfo.statistics.commentCount || 0);
                    totalViews += BigInt(videoInfo.statistics.viewCount || 0);
                    postCount += 1;

                    const youtubeVideo = {
                        users: socialMedia.users,
                        socialMedia: socialMedia,
                        youtubeChannel: channel,
                        title: videoInfo['snippet']['title'],
                        description: videoInfo['snippet']['description'],
                        channel_name: videoInfo['snippet']['channelTitle'],
                        published_at: moment(videoInfo['snippet']['publishedAt']).format('YYYY-MM-DD HH:mm:ss'),
                        thumbnails: videoInfo['snippet']['thumbnails']['medium']['url'],
                        localized: JSON.stringify(videoInfo['snippet']['localized']),
                        video_id: videoInfo['id'],
                        youtube_category_id: videoInfo['snippet']['categoryId'],
                        view_counts: videoInfo['statistics']['viewCount'],
                        like_counts: videoInfo['statistics']['likeCount'],
                        comment_count: videoInfo['statistics']['commentCount'],
                        favorite_count: videoInfo['statistics']['favoriteCount'],
                        post_url: `https://www.youtube.com/watch?v=${videoInfo['id']}`,
                    }
                    await this.YoutubeVideos.save(youtubeVideo);

                    const socialMediaPost = {
                        users: socialMedia.users,
                        socialMedia: socialMedia,
                        title: videoInfo['snippet']['title'],
                        description: videoInfo['snippet']['description'],
                        like_count: videoInfo['statistics']['likeCount'],
                        comment_count: videoInfo['statistics']['commentCount'],
                        post_id: videoInfo['id'],
                        post_url: `https://www.youtube.com/watch?v=${videoInfo['id']}`,
                        image_url: videoInfo['snippet']['thumbnails']['medium']['url'],
                        social_type: SocialType.YOUTUBE,
                        created_time: moment(videoInfo['snippet']['publishedAt']).format('YYYY-MM-DD HH:mm:ss'),
                    }
                    await this.SocialMediaPosts.save(socialMediaPost);
                }
            }

            // GET THE ENGAGEMENT RATE
            //    const engagementRate = ((Number(totalLikes) + Number(totalComments) + Number(totalViews)) / Number(postCount)) / socialMedia.follower_count * 100;
            if (totalViews) {
                const engagementRate = parseFloat(
                    (((Number(totalLikes) + Number(totalComments)) / Number(totalViews)) * 100).toFixed(4)
                );
                await this.updateSocialMediaEngagementRate(socialMedia.id, engagementRate);
            }

        }
        // Update nextPageToken for pagination
        nextPageToken = playListResponse.nextPageToken;
        // } while(!nextPageToken); // Continue if there's a nextPageToken
    }

    async updateSocialMediaEngagementRate(id, engagementRate) {
        const socialMedia = await this.SocialMedias.findOne({ where: { id: id } });

        const oldEngagementRate = socialMedia['engagement_rate'] || 0;
        socialMedia['old_engagement_rate'] = oldEngagementRate;
        socialMedia['engagement_rate'] = engagementRate;
        if (oldEngagementRate == 0.0000) {
            socialMedia['engagement_rate_percentage'] = 100;  // or 100, depending on logic.
        } else {
            socialMedia['engagement_rate_percentage'] = Math.abs((engagementRate - oldEngagementRate) / oldEngagementRate * 100);
        }
        await this.SocialMedias.save(socialMedia);
    }

    async getAxios(url, headers = {}, params = {}) {
        try {
            const response = await axios.get(url, {
                headers: headers,
                params: params,
            });
            // Handle the response data
            return response.data;

        } catch (error) {
            return false;
            // throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
        }
    }



}
