// Uber: POST/PUT *.uber.com/go/graphql yalnızca TripRequest → proxy.
// document_start + MAIN world; dış bağımlılık yoktur.

(function () {
  'use strict';

  // ─── Paylaşımlı callback haritaları ──────────────────────────────────────────
  (function ensureCallbackMaps() {
    if (!window.yemekTimeUber) {
      try {
        Object.defineProperty(window, 'yemekTimeUber', {
          value: { xhrCallbacks: {}, fetchCallbacks: {} },
          writable: false, configurable: false, enumerable: true,
        });
      } catch (_) {
        window.yemekTimeUber = { xhrCallbacks: {}, fetchCallbacks: {} };
      }
    } else {
      window.yemekTimeUber.xhrCallbacks   = window.yemekTimeUber.xhrCallbacks   || {};
      window.yemekTimeUber.fetchCallbacks = window.yemekTimeUber.fetchCallbacks || {};
    }
  })();

  function resolveUrl(url) {
    try { return new URL(url, window.location.href).href; }
    catch (_) { return url; }
  }


  // ─── GraphQL proxy — *.uber.com/go/graphql + TripRequest ───────────────────
  function isUberHost(hostname) {
    var h = (hostname || '').toLowerCase();
    return h === 'uber.com' || h === 'www.uber.com' || h.endsWith('.uber.com');
  }

  function isGoGraphQLEndpoint(url) {
    try {
      var u = new URL(url, window.location.href);
      return isUberHost(u.hostname) && u.pathname.toLowerCase() === '/go/graphql';
    } catch (_) { return false; }
  }

  function isTripRequestGraphQLBody(bodyStr) {
    if (!bodyStr || typeof bodyStr !== 'string') return false;
    try {
      var j = JSON.parse(bodyStr);
      var items = Array.isArray(j) ? j : [j];
      for (var i = 0; i < items.length; i++) {
        var item = items[i];
        if (!item || typeof item !== 'object') continue;
        if (String(item.operationName || '').toLowerCase() === 'triprequest') return true;
        if (typeof item.query === 'string' &&
            /mutation\s+TripRequest\b/i.test(item.query)) return true;
      }
    } catch (_) {}
    return false;
  }

  function bodyToString(body) {
    if (body == null) return Promise.resolve(null);
    if (typeof body === 'string') return Promise.resolve(body);
    if (body instanceof URLSearchParams) return Promise.resolve(body.toString());
    try {
      if (typeof ArrayBuffer !== 'undefined' && body instanceof ArrayBuffer) {
        return Promise.resolve(new TextDecoder('utf-8').decode(body));
      }
      if (typeof Uint8Array !== 'undefined' && ArrayBuffer.isView(body)) {
        return Promise.resolve(new TextDecoder('utf-8').decode(body));
      }
    } catch (_) {}
    if (typeof Blob !== 'undefined' && body instanceof Blob) {
      return body.text();
    }
    if (typeof Request !== 'undefined' && body instanceof Request) {
      try { return body.clone().text(); } catch (_) { return Promise.resolve(null); }
    }
    if (body && typeof body.text === 'function') {
      return body.text();
    }
    try { return Promise.resolve(String(body)); } catch (_) {
      return Promise.resolve(null);
    }
  }

  // ─── JA3/TLS fingerprint sızıntı tespiti: _events endpoint'leri ──────────────
  function isEventsEndpoint(url) {
    try {
      var p = new URL(url, window.location.href).pathname.toLowerCase();
      return p === '/_events' || p === '/go/_events';
    } catch (_) { return false; }
  }

  function shouldProxyGraphQL(url, method, bodyStr) {
    var mu = (method || 'GET').toUpperCase();
    if (mu !== 'POST' && mu !== 'PUT') return false;
    if (!isGoGraphQLEndpoint(url)) return false;
    return isTripRequestGraphQLBody(bodyStr);
  }

  function headersToPlain(h) {
    var out = {};
    if (!h) return out;
    if (typeof h.forEach === 'function') {
      try {
        h.forEach(function (v, k) { out[k] = v; });
      } catch (_) {}
      return out;
    }
    if (typeof h === 'object') {
      try { return Object.assign({}, h); } catch (_) {}
    }
    return out;
  }

  function mergePlainHeaders(a, b) {
    var out = Object.assign({}, a || {});
    if (!b) return out;
    var keys = Object.keys(b);
    for (var i = 0; i < keys.length; i++) {
      out[keys[i]] = b[keys[i]];
    }
    return out;
  }

  var EDGE_PATTERNS = [
    'edge_tls_ja3_fingerprint', 'tls_ja3', 'ja3_fingerprint', 'ja3_hash',
    '"browser":"edge"', '"browser":"chrome"', '"browser":"brave"',
    '"browser":"yandex"', '"browser":"opera"',
    '"browser": "edge"', '"browser": "chrome"', '"browser": "brave"',
  ];

  function hasEdgeJa3(bodyStr) {
    if (!bodyStr || typeof bodyStr !== 'string') return false;
    var lower = bodyStr.toLowerCase();
    for (var i = 0; i < EDGE_PATTERNS.length; i++) {
      if (lower.indexOf(EDGE_PATTERNS[i].toLowerCase()) !== -1) return true;
    }
    return false;
  }

  function makeFakeXhrOk(xhr) {
    Object.defineProperty(xhr, 'readyState',   { configurable: true, get: function () { return 4; } });
    Object.defineProperty(xhr, 'status',       { configurable: true, get: function () { return 200; } });
    Object.defineProperty(xhr, 'statusText',   { configurable: true, get: function () { return 'OK'; } });
    Object.defineProperty(xhr, 'responseText', { configurable: true, get: function () { return '{}'; } });
    Object.defineProperty(xhr, 'response',     { configurable: true, get: function () { return '{}'; } });
    setTimeout(function () {
      if (typeof xhr.onreadystatechange === 'function') xhr.onreadystatechange();
      if (typeof xhr.onload             === 'function') xhr.onload();
      if (typeof xhr.onloadend          === 'function') xhr.onloadend();
      try { xhr.dispatchEvent(new Event('readystatechange')); } catch (_) {}
      try { xhr.dispatchEvent(new Event('load')); }            catch (_) {}
      try { xhr.dispatchEvent(new Event('loadend')); }         catch (_) {}
    }, 0);
  }

  var PROXY_TIMEOUT_MS = 20000;

  function sendUberProxy(details) {
    return new Promise(function (resolve, reject) {
      var requestId = Date.now() + Math.random().toString().slice(2, 8);
      var settled   = false;

      var timer = setTimeout(function () {
        if (settled) return;
        settled = true;
        delete window.yemekTimeUber.fetchCallbacks[requestId];
        reject(new Error('Uber proxy timeout'));
      }, PROXY_TIMEOUT_MS);

      window.yemekTimeUber.fetchCallbacks[requestId] = function (response) {
        if (settled) return;
        settled = true;
        clearTimeout(timer);
        delete window.yemekTimeUber.fetchCallbacks[requestId];
        if (response && response.success) {
          resolve(response);
        } else {
          reject(new Error(response ? response.error : 'Proxy request failed'));
        }
      };

      window.postMessage({
        source:    'YEMEKTIME_UBER_EXT',
        action:    'uberProxyRequest',
        requestId: requestId,
        url:       details.url,
        method:    details.method,
        headers:   details.headers,
        body:      details.body,
      }, '*');
    });
  }

  window.addEventListener('message', function (event) {
    if (!event.data || event.data.source !== 'YEMEKTIME_UBER_EXT_CONTENT') return;
    if (event.data.action !== 'proxyResponse') return;
    var requestId = event.data.requestId;
    var response  = event.data.response;
    var mk        = window.yemekTimeUber;
    var xhrCb     = mk && mk.xhrCallbacks   && mk.xhrCallbacks[requestId];
    var fetchCb   = mk && mk.fetchCallbacks && mk.fetchCallbacks[requestId];
    if (xhrCb)   xhrCb(response);
    if (fetchCb) fetchCb(response);
  });

  var _origOpen      = XMLHttpRequest.prototype.open;
  var _origSend      = XMLHttpRequest.prototype.send;
  var _origSetHeader = XMLHttpRequest.prototype.setRequestHeader;

  XMLHttpRequest.prototype.open = function (method, url) {
    var args = Array.prototype.slice.call(arguments);
    this._uberUrl    = url;
    this._uberMethod = method;
    this._uberHeaders = {};

    var m = (method || 'GET').toUpperCase();
    if (m === 'POST' || m === 'PUT') {
      if (isGoGraphQLEndpoint(url)) {
        this._isUberCandidate = true;
      }
    }
    return _origOpen.apply(this, args);
  };

  XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
    if (this._isUberCandidate) {
      this._uberHeaders        = this._uberHeaders || {};
      this._uberHeaders[name]  = value;
    }
    return _origSetHeader.apply(this, arguments);
  };

  function dispatchUberXhrProxy(xhr, url, method, capturedHeaders, bodyStr) {
    xhr.abort();

    var requestId = Date.now() + Math.random().toString().slice(2, 8);
    window.yemekTimeUber.xhrCallbacks[requestId] = function (response) {
      if (response && response.success) {
        var data = response.data || '';
        Object.defineProperty(xhr, 'readyState',   { configurable: true, get: function () { return 4; } });
        Object.defineProperty(xhr, 'status',       { configurable: true, get: function () { return response.status || 200; } });
        Object.defineProperty(xhr, 'statusText',   { configurable: true, get: function () { return response.statusText || 'OK'; } });
        Object.defineProperty(xhr, 'responseText', { configurable: true, get: function () { return data; } });
        Object.defineProperty(xhr, 'response',     { configurable: true, get: function () { return data; } });
        setTimeout(function () {
          if (typeof xhr.onreadystatechange === 'function') xhr.onreadystatechange();
          if (typeof xhr.onload             === 'function') xhr.onload();
          if (typeof xhr.onloadend          === 'function') xhr.onloadend();
          try { xhr.dispatchEvent(new Event('readystatechange')); } catch (_) {}
          try { xhr.dispatchEvent(new Event('load')); }            catch (_) {}
          try { xhr.dispatchEvent(new Event('loadend')); }         catch (_) {}
        }, 0);
      } else {
        Object.defineProperty(xhr, 'readyState', { configurable: true, get: function () { return 4; } });
        Object.defineProperty(xhr, 'status',     { configurable: true, get: function () { return 0; } });
        setTimeout(function () {
          if (typeof xhr.onerror            === 'function') xhr.onerror();
          if (typeof xhr.onreadystatechange === 'function') xhr.onreadystatechange();
          if (typeof xhr.onloadend          === 'function') xhr.onloadend();
          try { xhr.dispatchEvent(new Event('error')); }            catch (_) {}
          try { xhr.dispatchEvent(new Event('readystatechange')); } catch (_) {}
          try { xhr.dispatchEvent(new Event('loadend')); }          catch (_) {}
        }, 50);
      }
      delete window.yemekTimeUber.xhrCallbacks[requestId];
    };

    window.postMessage({
      source:    'YEMEKTIME_UBER_EXT',
      action:    'uberProxyRequest',
      requestId: requestId,
      url:       resolveUrl(url),
      method:    method,
      headers:   capturedHeaders,
      body:      bodyStr,
    }, '*');
  }

  XMLHttpRequest.prototype.send = function (body) {
    var url    = this._uberUrl    || '';
    var method = this._uberMethod || 'GET';
    var xhr    = this;
    var isPost = (method || 'GET').toUpperCase() === 'POST' ||
                 (method || 'GET').toUpperCase() === 'PUT';

    function finishSend(bodyStr) {
      if (isPost && isEventsEndpoint(url) && hasEdgeJa3(bodyStr)) {
        xhr.abort();
        makeFakeXhrOk(xhr);
        return;
      }
      if (!shouldProxyGraphQL(url, method, bodyStr)) {
        return _origSend.call(xhr, body);
      }
      dispatchUberXhrProxy(
        xhr, url, method,
        Object.assign({}, xhr._uberHeaders || {}),
        bodyStr
      );
    }

    if (typeof body === 'string') {
      finishSend(body);
      return;
    }
    if (body != null && (isGoGraphQLEndpoint(url) || (isPost && isEventsEndpoint(url)))) {
      bodyToString(body).then(finishSend).catch(function () {
        _origSend.call(xhr, body);
      });
      return;
    }
    finishSend(null);
  };

  // ─── sendBeacon: JA3 sızıntısı içeren _events isteklerini engelle ───────────
  if (typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {
    var _origSendBeacon = navigator.sendBeacon.bind(navigator);
    navigator.sendBeacon = function (url, data) {
      try {
        var bodyStr = null;
        if (typeof data === 'string') bodyStr = data;
        else if (data && typeof data.toString === 'function') bodyStr = data.toString();

        if (isEventsEndpoint(url) && hasEdgeJa3(bodyStr)) {
          return true;
        }
      } catch (_) {}
      return _origSendBeacon(url, data);
    };
  }

  var _origFetch = window.fetch;

  window.fetch = function (resource, init) {
    init = init || {};
    var urlString = resource instanceof Request ? resource.url : String(resource);
    var method    = init.method ||
                    (resource instanceof Request ? resource.method : 'GET');

    var bodySource = null;
    if (init.body != null) {
      bodySource = init.body;
    } else if (resource instanceof Request && resource.body != null) {
      bodySource = resource;
    }

    return bodyToString(bodySource).then(function (bodyStr) {
      var isPost = method.toUpperCase() === 'POST' || method.toUpperCase() === 'PUT';

      if (isPost && isEventsEndpoint(urlString) && hasEdgeJa3(bodyStr)) {
        return new Response('{}', {
          status:  200, statusText: 'OK',
          headers: { 'Content-Type': 'application/json' },
        });
      }

      if (shouldProxyGraphQL(urlString, method, bodyStr)) {
        var headersPlain = {};
        if (resource instanceof Request) {
          headersPlain = mergePlainHeaders(headersPlain, headersToPlain(resource.headers));
        }
        if (init.headers) {
          headersPlain = mergePlainHeaders(headersPlain, headersToPlain(init.headers));
        }
        return sendUberProxy({
          url:     resolveUrl(urlString),
          method:  method,
          headers: headersPlain,
          body:    bodyStr,
        }).then(function (proxyResponse) {
          return new Response(proxyResponse.data || '', {
            status:     proxyResponse.status     || 200,
            statusText: proxyResponse.statusText || 'OK',
            headers:    proxyResponse.headers    || {},
          });
        }).catch(function () {
          return new Response(null, { status: 503, statusText: 'Proxy Service Unavailable' });
        });
      }

      return _origFetch.apply(window, arguments);
    });
  };

})();
