import { Injectable, Logger } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
import { firstValueFrom } from 'rxjs';
import { TrendItem, CollectorResult } from '../../common/interfaces/trend-item.interface';

// Các subreddit phổ biến theo category
const SUBREDDIT_MAP: Record<string, string[]> = {
    general: ['popular', 'all'],
    tech: ['technology', 'programming', 'webdev', 'artificial', 'MachineLearning'],
    news: ['worldnews', 'news', 'UpliftingNews'],
    science: ['science', 'space', 'Futurology'],
    business: ['business', 'Economics', 'stocks', 'CryptoCurrency'],
    vietnam: ['VietNam', 'vietnam'],
    japan: ['Japan', 'japanese'],
    entertainment: ['movies', 'gaming', 'Music'],
};

@Injectable()
export class RedditService {
    private readonly logger = new Logger(RedditService.name);
    private readonly baseUrl = 'https://www.reddit.com';
    private readonly userAgent: string;
    private readonly maxItems: number;

    constructor(
        private readonly httpService: HttpService,
        private readonly configService: ConfigService,
    ) {
        this.userAgent = this.configService.get<string>(
            'collector.redditUserAgent',
            'TrendHunter/1.0',
        );
        this.maxItems = this.configService.get<number>(
            'collector.maxItemsPerSource',
            25,
        );
    }

    async collect(
        categories: string[] = ['general', 'tech', 'news'],
    ): Promise<CollectorResult> {
        this.logger.debug('RedditService collect ...');
        const start = Date.now();
        const allItems: TrendItem[] = [];
        const errors: string[] = [];

        // Thu thập từ mỗi category
        const subreddits = categories.flatMap((cat) => SUBREDDIT_MAP[cat] || []);
        const uniqueSubreddits = [...new Set(subreddits)];

        const results = await Promise.allSettled(
            uniqueSubreddits.map((sub) => this.getHotPosts(sub)),
        );

        for (let i = 0; i < results.length; i++) {
            const result = results[i];
            if (result.status === 'fulfilled') {
                allItems.push(...result.value);
            } else {
                errors.push(`r/${uniqueSubreddits[i]}: ${result.reason?.message}`);
            }

            // Rate limiting: Reddit cho phép ~60 req/phút cho unauthenticated
            // Thêm delay nhỏ giữa mỗi request
            if (i < results.length - 1) {
                await this.sleep(500);
            }
        }

        this.logger.log(
            `Reddit collected: ${allItems.length} items from ${uniqueSubreddits.length} subreddits`,
        );

        return {
            source: 'reddit',
            items: allItems,
            collectedAt: new Date(),
            durationMs: Date.now() - start,
            error: errors.length > 0 ? errors.join('; ') : undefined,
        };
    }

    /**
     * Lấy hot posts từ 1 subreddit
     * Dùng .json endpoint — KHÔNG CẦN API KEY
     */
    private async getHotPosts(
        subreddit: string,
        limit: number = 15,
    ): Promise<TrendItem[]> {
        const { data } = await firstValueFrom(
            this.httpService.get(`${this.baseUrl}/r/${subreddit}/hot.json`, {
                params: {
                    limit: Math.min(limit, this.maxItems),
                    raw_json: 1,
                },
                headers: {
                    'User-Agent': this.userAgent,
                },
            }),
        );

        const posts = data?.data?.children || [];

        return posts
            .filter((post: any) => {
                // Bỏ stickied posts (thường là rules/announcements)
                return !post.data.stickied && post.data.title;
            })
            .map((post: any) => {
                const d = post.data;
                return {
                    source: `reddit:r/${subreddit}`,
                    title: d.title,
                    description: this.buildDescription(d),
                    url: d.url_overridden_by_dest || `https://reddit.com${d.permalink}`,
                    score: this.normalizeScore(d.score, d.num_comments, d.upvote_ratio),
                    timestamp: new Date(d.created_utc * 1000),
                    category: this.mapSubredditToCategory(subreddit),
                    tags: [
                        subreddit,
                        d.link_flair_text,
                    ].filter(Boolean),
                    engagement: {
                        upvotes: d.score,
                        comments: d.num_comments,
                        shares: d.num_crossposts || 0,
                    },
                    raw: {
                        subreddit: d.subreddit,
                        permalink: d.permalink,
                        upvoteRatio: d.upvote_ratio,
                        isOriginalContent: d.is_original_content,
                        flair: d.link_flair_text,
                        awards: d.total_awards_received,
                        thumbnail: d.thumbnail,
                        domain: d.domain,
                    },
                } as TrendItem;
            });
    }

    private buildDescription(postData: any): string {
        if (postData.selftext) {
            return postData.selftext.substring(0, 500);
        }
        if (postData.media?.reddit_video) {
            return `[Video] ${postData.title}`;
        }
        if (postData.post_hint === 'image') {
            return `[Image] ${postData.title}`;
        }
        return postData.title;
    }

    private normalizeScore(
        upvotes: number,
        comments: number,
        upvoteRatio: number,
    ): number {
        // Formula: engagement + controversy bonus
        const engagement = Math.log10(Math.max(upvotes, 1)) * 12;
        const commentBonus = Math.log10(Math.max(comments, 1)) * 8;
        // Controversial posts (ratio ~0.5) get a boost
        const controversyBonus = upvoteRatio < 0.7 ? 10 : 0;

        return Math.min(
            Math.round(engagement + commentBonus + controversyBonus),
            100,
        );
    }

    private mapSubredditToCategory(subreddit: string): string {
        for (const [category, subs] of Object.entries(SUBREDDIT_MAP)) {
            if (subs.map((s) => s.toLowerCase()).includes(subreddit.toLowerCase())) {
                return category;
            }
        }
        return 'general';
    }

    private sleep(ms: number): Promise<void> {
        return new Promise((resolve) => setTimeout(resolve, ms));
    }
}
