/* global window, FormData, fetch */
window.Niwa = window.Niwa || {};

window.Niwa.AdminChatTransport = (function () {
  'use strict';

  function create() {
    return {
      baseFormData: baseFormData,
      fetchAjax: fetchAjax,
      getNonce: getNonce,
      setNonce: setNonce
    };
  }

  function fetchAjax(formData, retried) {
    var ajaxUrl = window.NiwaAI && window.NiwaAI.ajax;
    if (!ajaxUrl) return Promise.reject(new Error('missing_ajax_url'));

    return fetch(ajaxUrl, {
      method: 'POST',
      body: formData,
      credentials: 'same-origin',
      headers: {
        'Accept': 'application/json',
        'X-Niwa-Admin-Chat': '1',
        'X-Requested-With': 'XMLHttpRequest'
      }
    }).then(function (response) {
      return response.text().then(function (raw) {
        return {
          raw: raw,
          status: response.status || 0,
          contentType: response.headers && response.headers.get ? (response.headers.get('content-type') || '') : ''
        };
      });
    }).then(function (payload) {
      var raw = payload && typeof payload.raw === 'string' ? payload.raw : '';
      var status = payload && payload.status ? parseInt(payload.status, 10) || 0 : 0;
      var parsed = parseJson(raw);
      if (parsed) {
        if (parsed.success === false && parsed.data && parsed.data.refresh_required && !retried) {
          return refreshNonce().then(function (fresh) {
            if (!fresh) return parsed;
            setNonce(fresh);
            replaceNonce(formData, fresh);
            return fetchAjax(formData, true);
          });
        }
        return parsed;
      }

      if (looksLikeBrowserChallenge(raw)) {
        return {
          success: false,
          data: {
            error: 'browser_security_challenge',
            message: buildBrowserChallengeMessage(status)
          }
        };
      }

      if (!retried && looksLikeHtml(raw)) {
        return refreshNonce().then(function (fresh) {
          if (!fresh) return null;
          setNonce(fresh);
          replaceNonce(formData, fresh);
          return fetchAjax(formData, true);
        });
      }

      if (status === 403 && looksLikeHtml(raw)) {
        return {
          success: false,
          data: {
            error: 'http_403_html',
            message: buildBrowserChallengeMessage(status)
          }
        };
      }

      return null;
    });
  }

  function refreshNonce() {
    var fd = baseFormData('niwa_ai_refresh_nonce');
    fd.append('scope', 'admin_autonomy');
    return fetch((window.NiwaAI && window.NiwaAI.ajax) || '', {
      method: 'POST',
      body: fd,
      credentials: 'same-origin',
      headers: {
        'Accept': 'application/json',
        'X-Niwa-Admin-Chat': '1',
        'X-Requested-With': 'XMLHttpRequest'
      }
    }).then(function (response) {
      return response.text();
    }).then(function (raw) {
      var parsed = parseJson(raw);
      return parsed && parsed.success && parsed.data && parsed.data.nonce ? parsed.data.nonce : '';
    }).catch(function () {
      return '';
    });
  }

  function baseFormData(action) {
    var fd = new FormData();
    fd.append('action', action);
    return fd;
  }

  function parseJson(raw) {
    if (raw && typeof raw === 'object') return raw;
    if (typeof raw !== 'string') return null;
    try {
      return JSON.parse(raw);
    } catch (e) {
      return null;
    }
  }

  function looksLikeHtml(raw) {
    return typeof raw === 'string' && /^\s*</.test(raw);
  }

  function looksLikeBrowserChallenge(raw) {
    if (typeof raw !== 'string' || !raw) return false;
    var haystack = raw.toLowerCase();
    return haystack.indexOf('checking your browser before accessing') !== -1
      || haystack.indexOf('/cdn-cgi/challenge-platform/') !== -1
      || haystack.indexOf('/hcdn-cgi/jschallenge') !== -1
      || haystack.indexOf('x-hcdn-request-id') !== -1
      || haystack.indexOf('please check that your browser supports javascript') !== -1
      || haystack.indexOf('verify you are human') !== -1
      || haystack.indexOf('verify that you are not a robot') !== -1
      || haystack.indexOf('are you a human') !== -1
      || haystack.indexOf('bot verification') !== -1
      || haystack.indexOf('security check') !== -1
      || haystack.indexOf('js challenge') !== -1
      || haystack.indexOf('javascript challenge') !== -1
      || haystack.indexOf('just a moment') !== -1
      || haystack.indexOf('cf-chl-') !== -1
      || haystack.indexOf('cloudflare') !== -1
      || haystack.indexOf('sucuri') !== -1
      || haystack.indexOf('incapsula') !== -1
      || haystack.indexOf('imperva') !== -1
      || haystack.indexOf('imunify360') !== -1
      || haystack.indexOf('bitninja') !== -1;
  }

  function buildBrowserChallengeMessage(status) {
    var prefix = status ? 'Hosting/CDN security returned HTTP ' + status + '. ' : '';
    return prefix + 'A browser verification or bot-check blocked this admin chat request before WordPress could process it. Complete the verification, reload the page, and send the message again.';
  }

  function getNonce() {
    return (window.NiwaAI && window.NiwaAI.nonce) || '';
  }

  function setNonce(nonce) {
    if (window.NiwaAI) {
      window.NiwaAI.nonce = nonce;
    }
  }

  function replaceNonce(formData, nonce) {
    try {
      if (formData.has('nonce')) formData.set('nonce', nonce);
      if (formData.has('_ajax_nonce')) formData.set('_ajax_nonce', nonce);
    } catch (e) { /* ignore */ }
  }

  return {
    create: create
  };
})();
