import {Readable} from 'stream';

interface ProxyHeaders {
    referer?: string;
    origin?: string;
    userAgent?: string;
}

interface ProxyResponse {
    response: Response;
    contentType: string | null;
    isM3U8: boolean;
    contentLength: string | null;
}

export async function proxyRequest(url: string, { referer, origin, userAgent }: ProxyHeaders, rangeHeader?: string): Promise<ProxyResponse> {
    const headers: Record<string, string> = {
        'User-Agent': userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        'Accept': '*/*',
        'Accept-Language': 'en-US,en;q=0.9',
        'Accept-Encoding': 'identity',
        'Connection': 'keep-alive'
    };

    if (referer) headers['Referer'] = referer;
    if (origin) headers['Origin'] = origin;
    if (rangeHeader) headers['Range'] = rangeHeader;

    let lastError: Error | null = null;
    const maxRetries = 2;

    for (let attempt = 0; attempt < maxRetries; attempt++) {
        try {
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), 60000);

            const response = await fetch(url, {
                headers,
                redirect: 'follow',
                signal: controller.signal
            });

            clearTimeout(timeoutId);

            if (!response.ok && response.status !== 206) {
                if (response.status === 404 || response.status === 403) {
                    throw new Error(`Proxy Error: ${response.status} ${response.statusText}`);
                }

                if (attempt < maxRetries - 1) {
                    await new Promise(resolve => setTimeout(resolve, 500));
                    continue;
                }

                throw new Error(`Proxy Error: ${response.status} ${response.statusText}`);
            }

            const contentLength = response.headers.get('content-length');
            const contentType = response.headers.get('content-type');
            const ct = contentType?.toLowerCase();

            const isM3U8 =
                !!ct && (
                    ct.includes('mpegurl') ||
                    ct.includes('m3u8')
                ) ||
                url.toLowerCase().includes('.m3u8');

            return {
                response,
                contentType,
                isM3U8,
                contentLength
            };

        } catch (error) {
            lastError = error as Error;

            if (attempt === maxRetries - 1) {
                throw lastError;
            }

            await new Promise(resolve => setTimeout(resolve, 500));
        }
    }

    throw lastError || new Error('Unknown error in proxyRequest');
}

export function processM3U8Content(text: string, baseUrl: URL, { referer, origin, userAgent }: ProxyHeaders): string {
    const buildProxy = (url: string) => {
        try {
            const params = new URLSearchParams();
            params.set('url', new URL(url, baseUrl).href);
            if (referer) params.set('referer', referer);
            if (origin) params.set('origin', origin);
            if (userAgent) params.set('userAgent', userAgent);
            return `/api/proxy?${params.toString()}`;
        } catch (error) {
            console.error('Error building proxy URL for:', url, error);
            return url;
        }
    };

    const isMasterPlaylist = text.includes('#EXT-X-STREAM-INF');


    let lines = text.split('\n');
    let result = [];

    for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        const trimmed = line.trim();

        if (!trimmed) {
            result.push(line);
            continue;
        }

        if (trimmed.startsWith('#')) {
            if (line.includes('URI=')) {
                const processedLine = line.replace(/URI="([^"]+)"/g, (match, uri) => {
                    return `URI="${buildProxy(uri)}"`;
                });
                result.push(processedLine);
            } else {
                result.push(line);
            }
            continue;
        }

        try {
            const proxiedUrl = buildProxy(trimmed);
            result.push(proxiedUrl);
        } catch (error) {
            console.error('Error processing M3U8 URL line:', trimmed, error);
            result.push(line);
        }
    }

    return result.join('\n');
}

export function streamToReadable(webStream: ReadableStream): Readable {
    const reader = webStream.getReader();
    let readTimeout: NodeJS.Timeout;

    return new Readable({
        async read() {
            try {
                const timeoutPromise = new Promise((_, reject) => {
                    readTimeout = setTimeout(() => reject(new Error('Stream read timeout')), 10000);
                });

                const readPromise = reader.read();
                const { done, value } = await Promise.race([readPromise, timeoutPromise]) as any;

                clearTimeout(readTimeout);

                if (done) {
                    this.push(null);
                } else {
                    this.push(Buffer.from(value));
                }
            } catch (error) {
                clearTimeout(readTimeout);
                this.destroy(error as Error);
            }
        },
        destroy(error, callback) {
            clearTimeout(readTimeout);
            reader.cancel().then(() => callback(error)).catch(callback);
        }
    });
}