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';

@Injectable()
export class HackerNewsService {
    private readonly logger = new Logger(HackerNewsService.name);
    private readonly baseUrl = 'https://hacker-news.firebaseio.com/v0';
    private readonly maxItems: number;

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

    async collect(): Promise<CollectorResult> {
        const start = Date.now();
        const items: TrendItem[] = [];
        const errors: string[] = [];

        // Thu thập từ cả 3 endpoint
        const endpoints = [
            { name: 'top', fn: () => this.getStories('topstories') },
            { name: 'best', fn: () => this.getStories('beststories') },
            { name: 'new-hot', fn: () => this.getNewHotStories() },
        ];

        for (const ep of endpoints) {
            try {
                const stories = await ep.fn();
                items.push(...stories);
            } catch (e) {
                errors.push(`${ep.name}: ${e.message}`);
            }
        }

        // Dedup bởi URL (vì top/best có thể overlap)
        const seen = new Set<string>();
        const deduped = items.filter((item) => {
            if (seen.has(item.url)) return false;
            seen.add(item.url);
            return true;
        });

        this.logger.log(`HackerNews collected: ${deduped.length} items`);

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

    /**
     * Lấy stories từ endpoint (topstories / beststories / newstories)
     * 100% FREE, UNLIMITED, không cần API key
     */
    private async getStories(
        endpoint: string,
        limit?: number,
    ): Promise<TrendItem[]> {
        const effectiveLimit = limit || this.maxItems;

        // 1. Lấy danh sách IDs
        const { data: storyIds } = await firstValueFrom(
            this.httpService.get<number[]>(`${this.baseUrl}/${endpoint}.json`),
        );

        const topIds = storyIds.slice(0, effectiveLimit);

        // 2. Lấy chi tiết song song (batch 10 để tránh quá nhiều concurrent)
        const stories: TrendItem[] = [];
        const batchSize = 10;

        for (let i = 0; i < topIds.length; i += batchSize) {
            const batch = topIds.slice(i, i + batchSize);
            const batchResults = await Promise.allSettled(
                batch.map((id) => this.getStoryDetail(id)),
            );

            for (const result of batchResults) {
                if (result.status === 'fulfilled' && result.value) {
                    stories.push({
                        ...result.value,
                        // Score dựa trên position trong list
                        score: Math.max(
                            result.value.score,
                            100 - Math.round((stories.length / effectiveLimit) * 80),
                        ),
                    });
                }
            }
        }

        return stories;
    }

    /**
     * Lọc new stories có engagement cao (rising trends)
     */
    private async getNewHotStories(): Promise<TrendItem[]> {
        const { data: newIds } = await firstValueFrom(
            this.httpService.get<number[]>(`${this.baseUrl}/newstories.json`),
        );

        // Lấy 50 bài mới nhất, filter lấy những bài nào có điểm cao
        const topNewIds = newIds.slice(0, 50);
        const batchSize = 10;
        const hotNew: TrendItem[] = [];

        for (let i = 0; i < topNewIds.length; i += batchSize) {
            const batch = topNewIds.slice(i, i + batchSize);
            const results = await Promise.allSettled(
                batch.map((id) => this.getStoryDetail(id)),
            );

            for (const result of results) {
                if (result.status === 'fulfilled' && result.value) {
                    const item = result.value;
                    // Chỉ lấy những bài mới nhưng đã có engagement
                    const points = item.engagement?.upvotes || 0;
                    const comments = item.engagement?.comments || 0;
                    if (points >= 5 || comments >= 3) {
                        hotNew.push({
                            ...item,
                            source: 'hackernews:rising',
                            // Rising trend bonus
                            score: Math.min(item.score + 15, 100),
                        });
                    }
                }
            }
        }

        return hotNew;
    }

    private async getStoryDetail(id: number): Promise<TrendItem | null> {
        const { data } = await firstValueFrom(
            this.httpService.get(`${this.baseUrl}/item/${id}.json`),
        );

        if (!data || data.deleted || data.dead) return null;

        const points = data.score || 0;
        const comments = data.descendants || 0;

        return {
            source: 'hackernews',
            title: data.title || '',
            description: data.text
                ? data.text.replace(/<[^>]*>/g, '').substring(0, 500)
                : '',
            url: data.url || `https://news.ycombinator.com/item?id=${id}`,
            score: this.calculateScore(points, comments),
            timestamp: new Date((data.time || 0) * 1000),
            category: 'tech',
            tags: this.extractDomain(data.url),
            engagement: {
                upvotes: points,
                comments,
            },
            raw: {
                hnId: id,
                by: data.by,
                type: data.type,
                domain: data.url ? new URL(data.url).hostname : 'news.ycombinator.com',
                hnUrl: `https://news.ycombinator.com/item?id=${id}`,
            },
        };
    }

    private calculateScore(points: number, comments: number): number {
        const pointScore = Math.log10(Math.max(points, 1)) * 20;
        const commentScore = Math.log10(Math.max(comments, 1)) * 10;
        return Math.min(Math.round(pointScore + commentScore), 100);
    }

    private extractDomain(url?: string): string[] {
        if (!url) return [];
        try {
            const hostname = new URL(url).hostname.replace('www.', '');
            return [hostname];
        } catch {
            return [];
        }
    }
}
