/**
 * Cellframe Wallet iOS Bridge Polyfill
 * 
 * Intercepts fetch() and XMLHttpRequest calls to localhost:8045
 * and routes them through WKScriptMessageHandler bridge.
 * 
 * This allows dApps in WKWebView to communicate with the wallet's
 * HTTP API without direct localhost access (which iOS blocks).
 */

(function() {
    'use strict';
    
    // Check if already injected
    if (window.__cellframeBridgeInjected) {
        console.log('[CellframeBridge] Already injected, skipping');
        return;
    }
    window.__cellframeBridgeInjected = true;
    
    const LOCALHOST_PATTERN = /^https?:\/\/(localhost|127\.0\.0\.1):8045/i;
    const BRIDGE_NAME = 'cellframeBridge';
    
    // Pending requests storage
    let requestId = 0;
    const pendingRequests = new Map();
    
    // Check if bridge is available
    function hasBridge() {
        var available = window.webkit && 
               window.webkit.messageHandlers && 
               window.webkit.messageHandlers[BRIDGE_NAME];
        console.log('[CellframeBridge] Bridge check:', available ? 'AVAILABLE' : 'NOT AVAILABLE');
        if (window.webkit && window.webkit.messageHandlers) {
            console.log('[CellframeBridge] Available handlers:', Object.keys(window.webkit.messageHandlers));
        } else {
            console.log('[CellframeBridge] window.webkit.messageHandlers is:', window.webkit ? 'undefined' : 'window.webkit is null');
        }
        return !!available;
    }
    
    // Check if URL should be intercepted
    function shouldIntercept(url) {
        if (!url) return false;
        const urlStr = url.toString();
        return LOCALHOST_PATTERN.test(urlStr);
    }
    
    // Rewrite https to http for localhost URLs
    function rewriteToHttp(url) {
        if (!url) return url;
        const urlStr = url.toString();
        if (urlStr.match(/^https:\/\/(localhost|127\.0\.0\.1)/i)) {
            const rewritten = urlStr.replace(/^https:\/\//i, 'http://');
            console.log('[CellframeBridge] Rewriting https->http:', urlStr, '->', rewritten);
            return rewritten;
        }
        return url;
    }
    
    // Send request through bridge
    function sendBridgeRequest(method, url, headers, body) {
        return new Promise((resolve, reject) => {
            console.log('[CellframeBridge] sendBridgeRequest called:', method, url);
            
            if (!hasBridge()) {
                console.error('[CellframeBridge] REJECTED: Cellframe bridge not available');
                reject(new Error('Cellframe bridge not available'));
                return;
            }
            
            const id = ++requestId;
            
            // Store promise callbacks
            pendingRequests.set(id, { resolve, reject });
            
            // Parse URL to get query string
            let urlObj;
            try {
                urlObj = new URL(url);
            } catch (e) {
                urlObj = new URL(url, window.location.origin);
            }
            
            const message = {
                id: id,
                method: method,
                path: urlObj.pathname,
                query: urlObj.search,
                headers: headers || {},
                body: body || null,
                // Include page origin for dApp identification
                pageUrl: window.location.href,
                pageOrigin: window.location.origin,
                pageHost: window.location.host
            };
            
            console.log('[CellframeBridge] Sending request:', id, method, urlObj.pathname + urlObj.search);
            
            try {
                var msg = JSON.stringify(message);
                console.log('[CellframeBridge] POSTING message to native:', msg.substring(0, 200));
                window.webkit.messageHandlers[BRIDGE_NAME].postMessage(msg);
                console.log('[CellframeBridge] Message posted successfully');
            } catch (e) {
                console.error('[CellframeBridge] POST FAILED:', e.message);
                pendingRequests.delete(id);
                reject(new Error('Bridge communication failed: ' + e.message));
            }
            
            // Timeout after 30 seconds
            setTimeout(() => {
                if (pendingRequests.has(id)) {
                    console.error('[CellframeBridge] REQUEST TIMEOUT for id:', id);
                    pendingRequests.delete(id);
                    reject(new Error('Bridge request timeout'));
                }
            }, 30000);
            
            console.log('[CellframeBridge] Request sent, waiting for response, id:', id);
        });
    }
    
    // Handle response from native side
    window.__cellframeBridgeCallback = function(responseJson) {
        console.log('[CellframeBridge] CALLBACK RECEIVED:', responseJson.substring(0, 200));
        try {
            const response = JSON.parse(responseJson);
            const id = response.id;
            const pending = pendingRequests.get(id);
            
            if (pending) {
                pendingRequests.delete(id);
                
                if (response.error) {
                    pending.reject(new Error(response.error));
                } else {
                    pending.resolve({
                        status: response.status || 200,
                        statusText: response.statusText || 'OK',
                        headers: response.headers || {},
                        body: response.body || ''
                    });
                }
            }
        } catch (e) {
            console.error('[CellframeBridge] Callback parse error:', e);
        }
    };
    
    // ==================== Fetch Polyfill ====================
    
    const originalFetch = window.fetch;
    
    window.fetch = function(input, init) {
        let url = input;
        if (input instanceof Request) {
            url = input.url;
        }
        
        console.log('[CellframeBridge] fetch() called with URL:', url);
        
        if (!shouldIntercept(url)) {
            console.log('[CellframeBridge] fetch() NOT intercepted, passing through:', url);
            return originalFetch.apply(this, arguments);
        }
        
        url = rewriteToHttp(url);
        console.log('[CellframeBridge] fetch() INTERCEPTED:', url);
        
        const method = (init && init.method) || 'GET';
        const headers = {};
        
        if (init && init.headers) {
            if (init.headers instanceof Headers) {
                init.headers.forEach((value, key) => { headers[key] = value; });
            } else if (typeof init.headers === 'object') {
                Object.assign(headers, init.headers);
            }
        }
        
        const body = init ? init.body : null;
        
        return sendBridgeRequest(method, url, headers, body)
            .then(result => {
                // Create Response object
                const responseInit = {
                    status: result.status,
                    statusText: result.statusText,
                    headers: new Headers(result.headers)
                };
                return new Response(result.body, responseInit);
            });
    };
    
    // ==================== XMLHttpRequest Polyfill ====================
    
    const OriginalXHR = window.XMLHttpRequest;
    
    function PatchedXHR() {
        const xhr = new OriginalXHR();
        const self = this;
        
        // Internal state
        let intercepted = false;
        let method = 'GET';
        let url = '';
        let requestHeaders = {};
        let responseHeaders = {};
        let responseText = '';
        let responseStatus = 0;
        let responseStatusText = '';
        let readyState = 0;
        let async = true;
        
        // Event handlers
        this.onreadystatechange = null;
        this.onload = null;
        this.onerror = null;
        this.onloadend = null;
        this.ontimeout = null;
        this.onprogress = null;
        
        // Properties
        Object.defineProperty(this, 'readyState', { get: () => intercepted ? readyState : xhr.readyState });
        Object.defineProperty(this, 'status', { get: () => intercepted ? responseStatus : xhr.status });
        Object.defineProperty(this, 'statusText', { get: () => intercepted ? responseStatusText : xhr.statusText });
        Object.defineProperty(this, 'responseText', { get: () => intercepted ? responseText : xhr.responseText });
        Object.defineProperty(this, 'response', { get: () => intercepted ? responseText : xhr.response });
        Object.defineProperty(this, 'responseType', { 
            get: () => xhr.responseType,
            set: (v) => { xhr.responseType = v; }
        });
        Object.defineProperty(this, 'timeout', { 
            get: () => xhr.timeout,
            set: (v) => { xhr.timeout = v; }
        });
        Object.defineProperty(this, 'withCredentials', { 
            get: () => xhr.withCredentials,
            set: (v) => { xhr.withCredentials = v; }
        });
        
        // Methods
        this.open = function(m, u, a) {
            method = m;
            url = u;
            async = a !== false;
            requestHeaders = {};
            
            console.log('[CellframeBridge] XHR.open() called:', m, u);
            
            if (shouldIntercept(u)) {
                intercepted = true;
                url = rewriteToHttp(u);
                readyState = 1; // OPENED
                console.log('[CellframeBridge] XHR INTERCEPTED:', method, url);
            } else {
                intercepted = false;
                console.log('[CellframeBridge] XHR NOT intercepted, passing through:', u);
                xhr.open.apply(xhr, arguments);
            }
        };
        
        this.setRequestHeader = function(name, value) {
            if (intercepted) {
                requestHeaders[name] = value;
            } else {
                xhr.setRequestHeader(name, value);
            }
        };
        
        this.getResponseHeader = function(name) {
            if (intercepted) {
                return responseHeaders[name.toLowerCase()] || null;
            }
            return xhr.getResponseHeader(name);
        };
        
        this.getAllResponseHeaders = function() {
            if (intercepted) {
                return Object.entries(responseHeaders)
                    .map(([k, v]) => k + ': ' + v)
                    .join('\r\n');
            }
            return xhr.getAllResponseHeaders();
        };
        
        this.abort = function() {
            if (!intercepted) {
                xhr.abort();
            }
        };
        
        this.send = function(body) {
            if (!intercepted) {
                console.log('[CellframeBridge] XHR.send() passing through (not intercepted)');
                // Forward events for non-intercepted requests
                xhr.onreadystatechange = () => {
                    if (self.onreadystatechange) self.onreadystatechange();
                };
                xhr.onload = (e) => { if (self.onload) self.onload(e); };
                xhr.onerror = (e) => { if (self.onerror) self.onerror(e); };
                xhr.onloadend = (e) => { if (self.onloadend) self.onloadend(e); };
                xhr.ontimeout = (e) => { if (self.ontimeout) self.ontimeout(e); };
                xhr.onprogress = (e) => { if (self.onprogress) self.onprogress(e); };
                
                xhr.send(body);
                return;
            }
            
            // Intercepted request - use bridge
            sendBridgeRequest(method, url, requestHeaders, body)
                .then(result => {
                    responseStatus = result.status;
                    responseStatusText = result.statusText;
                    responseHeaders = {};
                    
                    // Normalize header names to lowercase
                    if (result.headers) {
                        Object.entries(result.headers).forEach(([k, v]) => {
                            responseHeaders[k.toLowerCase()] = v;
                        });
                    }
                    
                    responseText = result.body;
                    
                    // Fire events
                    readyState = 2; // HEADERS_RECEIVED
                    if (self.onreadystatechange) self.onreadystatechange();
                    
                    readyState = 3; // LOADING
                    if (self.onreadystatechange) self.onreadystatechange();
                    
                    readyState = 4; // DONE
                    if (self.onreadystatechange) self.onreadystatechange();
                    if (self.onload) self.onload({});
                    if (self.onloadend) self.onloadend({});
                })
                .catch(error => {
                    console.error('[CellframeBridge] XHR error:', error);
                    readyState = 4;
                    responseStatus = 0;
                    if (self.onreadystatechange) self.onreadystatechange();
                    if (self.onerror) self.onerror({ error: error.message });
                    if (self.onloadend) self.onloadend({});
                });
        };
        
        // EventTarget methods
        this.addEventListener = function(type, listener) {
            if (!intercepted) {
                xhr.addEventListener(type, listener);
            }
        };
        this.removeEventListener = function(type, listener) {
            if (!intercepted) {
                xhr.removeEventListener(type, listener);
            }
        };
    }
    
    // Replace XMLHttpRequest
    window.XMLHttpRequest = PatchedXHR;
    
    // Keep reference to original
    window.XMLHttpRequest.UNSENT = 0;
    window.XMLHttpRequest.OPENED = 1;
    window.XMLHttpRequest.HEADERS_RECEIVED = 2;
    window.XMLHttpRequest.LOADING = 3;
    window.XMLHttpRequest.DONE = 4;
    
    // ==================== WebSocket Interception ====================
    
    const OriginalWebSocket = window.WebSocket;
    
    window.WebSocket = function(url, protocols) {
        const wsUrl = shouldIntercept(url) 
            ? url.replace(/^wss:\/\//i, 'ws://').replace(/^https:\/\//i, 'http://')
            : url;
        console.log('[CellframeBridge] WebSocket connecting to:', wsUrl);
        
        if (protocols !== undefined) {
            return new OriginalWebSocket(wsUrl, protocols);
        }
        return new OriginalWebSocket(wsUrl);
    };
    window.WebSocket.prototype = OriginalWebSocket.prototype;
    window.WebSocket.CONNECTING = OriginalWebSocket.CONNECTING;
    window.WebSocket.OPEN = OriginalWebSocket.OPEN;
    window.WebSocket.CLOSING = OriginalWebSocket.CLOSING;
    window.WebSocket.CLOSED = OriginalWebSocket.CLOSED;
    
    console.log('[CellframeBridge] iOS Bridge polyfill injected successfully');
    console.log('[CellframeBridge] Bridge available:', hasBridge());
})();

