import {exec} from 'child_process';
import {promisify} from 'util';
import path from 'path';
import fs from 'fs';
import {BadRequestException, Injectable, Logger} from "@nestjs/common";
import axios from "axios";
import {pipeline} from 'stream/promises';

const execAsync = promisify(exec);

@Injectable()
export class XTiktokDownloadService {
    private readonly logger = new Logger(XTiktokDownloadService.name);
    private downloadDir = './downloads/'

    constructor() {
        fs.mkdirSync(this.downloadDir, {recursive: true});
        // fs.mkdirSync(this.downloadDir + '/fb', {recursive: true});
        // fs.mkdirSync(this.downloadDir + '/tiktok', {recursive: true});
        // fs.mkdirSync(this.downloadDir + '/x', {recursive: true});
        // fs.mkdirSync(this.downloadDir + '/yt', {recursive: true});

    }

    async download(url: string) {
        const urlMp4Regex = /(https?:\/\/[^\s]+\.mp4)/i;
        if (urlMp4Regex.test(url)) {
            return this.downloadUrlMp4(url, '');
        }
        if (url.indexOf('tiktok')) {
            return this.downloadTikTok(url);
        }
        const regexFb = /https?:\/\/(www\.)?(facebook\.com\/reel\/\S+|fb\.watch\/\S+)/i
        if (regexFb.test(url)) {
            return this.downloadFacebookReels(url);
        }
        return {
            status: 0,
            filePath: '',
            title: '',
            error: ''
        }
    }

    async downloadTikTok(url) {
        const timestamp = Date.now();
        const outputDir = path.resolve('./downloads/tiktok');
        const outputTemplate = path.join(outputDir, `tt_${timestamp}.%(ext)s`);

        // yt-dlp: tải TikTok không watermark, output mp4
        const cmd = `yt-dlp -f "best[ext=mp4]/best" -o "${outputTemplate}" --no-warnings "${url}"`;

        try {
            const {stdout} = await execAsync(cmd, {maxBuffer: 1024 * 1024 * 50});

            // Tìm file vừa download
            const files = fs.readdirSync(outputDir)
                .filter(f => f.startsWith(`tt_${timestamp}`))
                .map(f => path.join(outputDir, f));

            if (!files.length) throw new Error('Không tìm thấy file đã tải');
            console.log({files});
            return {
                filePath: files[0],
                title: `TikTok_${timestamp}`,
                status: 1,
                error: ''
            };
        } catch (err) {
            throw new Error(`Lỗi download TikTok: ${err.message}`);
        }
    }

    // async downloadVideoQueue(url) {}
    async downloadUrlMp4(mp4url: string, sourceType = '') {
        const dir = this.downloadDir + `/${sourceType}`;
        fs.mkdirSync(dir, {recursive: true});
        console.log('downloadUrlMp4:', mp4url);
        // const filename = customName || this.extractFilename(mp4url);

        this.logger.log(`⬇️  Đang tải: ${mp4url}`);
        const timestamp = Date.now();
        const filename = `${sourceType}_${timestamp}.mp4`;
        const filePath = path.join(dir, filename);


        const response = await axios({
            url: mp4url,
            method: 'GET',
            responseType: 'stream',
            timeout: 80000,
            headers: {
                'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                Accept: 'video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5',
            },
        });

        const writer = fs.createWriteStream(filePath);
        await pipeline(response.data, writer);

        // await new Promise((resolve, reject) => {
        //     const writer = fs.createWriteStream(filePath);
        //     response.data.pipe(writer);
        //     writer.on('finish', ()=>{
        //         console.log(`download ${mp4url} done`);
        //         resolve(filePath);
        //     });
        //     writer.on('error', reject);
        // });
        console.log('✅ Tải xong:', mp4url);
        return {
            filePath,
            title: filename,
            status: 1,
            error: ''
        };
    }

    /**
     * Download Facebook Reels
     */
    async downloadFacebookReels(fbUrl: string) {
        this.logger.log(`🔍 Đang phân tích Facebook Reels: ${fbUrl}`);

        // Chuẩn hóa URL
        let targetUrl = fbUrl.trim();
        if (!targetUrl.startsWith('http')) targetUrl = `https://${targetUrl}`;

        // 1. Lấy HTML trang reels
        const html = await this.fetchFacebookPage(targetUrl);

        // 2. Trích xuất direct video URL từ HTML
        const videoUrl = this.extractFacebookVideoUrl(html);
        if (!videoUrl) {
            throw new BadRequestException('Không tìm thấy video URL trong trang Facebook. Có thể reels bị giới hạn hoặc Facebook đã đổi cấu trúc.');
        }

        this.logger.log(`📹 Tìm thấy video source: ${videoUrl.substring(0, 100)}...`);

        // 3. Tải về bằng axios stream
        return this.downloadUrlMp4(videoUrl, 'fb');
    }

    /**
     * Lấy HTML của trang Facebook (giả lập browser desktop)
     */
    private async fetchFacebookPage(url: string): Promise<string> {
        try {
            const {data} = await axios.get(url, {
                timeout: 30000,
                maxRedirects: 5,
                headers: {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                    'Accept-Language': 'en-US,en;q=0.9',
                    Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
                    'Cache-Control': 'max-age=0',
                    'sec-fetch-dest': 'document',
                    'sec-fetch-mode': 'navigate',
                    'sec-fetch-site': 'none',
                    'sec-fetch-user': '?1',
                    'upgrade-insecure-requests': '1',
                },
            });
            return data as string;
        } catch (err: any) {
            this.logger.error(`Lỗi fetch Facebook page: ${err.message}`);
            throw new BadRequestException(`Không thể truy cập link Facebook: ${err.message}`);
        }
    }

    /**
     * Parse HTML Facebook để tìm video URL trực tiếp
     */
    private extractFacebookVideoUrl(html: string): string | null {
        // Cách 1: Meta tag og:video hoặc og:video:url
        const ogVideoMatch = html.match(/<meta[^>]+property=["']og:video(:(url|secure_url))?["'][^>]+content=["']([^"']+)["']/i);
        if (ogVideoMatch) {
            const url = ogVideoMatch[3];
            // Loại bỏ HTML entities
            return url.replace(/&amp;/g, '&');
        }

        // Cách 2: Tìm trong script JSON chứa "video_url" hoặc "browser_native_sd_url"
        const patterns = [
            /"video_url"\s*:\s*"([^"]+)"/,
            /"browser_native_sd_url"\s*:\s*"([^"]+)"/,
            /"browser_native_hd_url"\s*:\s*"([^"]+)"/,
            /"playable_url"\s*:\s*"([^"]+)"/,
            /"playable_url_quality_hd"\s*:\s*"([^"]+)"/,
        ];

        for (const pattern of patterns) {
            const match = html.match(pattern);
            if (match) {
                return match[1].replace(/\\u0025/g, '%').replace(/\\/g, '');
            }
        }

        // Cách 3: Tìm trong data-store hoặc các cấu trúc deferred data
        const deferredMatch = html.match(/video_url\\":\\"([^"]+)\\"/);
        if (deferredMatch) {
            return deferredMatch[1].replace(/\\/g, '');
        }

        return null;
    }

    private extractFilename(url: string): string {
        try {
            const name = path.basename(new URL(url).pathname);
            if (name && name.includes('.')) return name;
        } catch { /* ignore */
        }
        return `video_${Date.now()}.mp4`;
    }
}
