export interface ShellIdentity {
  externalId: string;
  email?: string;
  name?: string;
  phone?: string;
  contactCompany?: string;
  contactCompanyExternalId?: string;
  country?: string;
  customFields?: Record<string, string | number | boolean>;
  identityToken?: string;
  identitySignature?: string;
  providesProof: boolean;
}

export interface WidgetShellOptions {
  bundle: string | null;
  scriptUrl: string | null;
  publishableKey: string;
  apiBaseUrl: string;
  language: 'es' | 'en';
  tabId: string;
  primaryColor: string | null;
  identity: ShellIdentity | null;
}

const MESSAGE_CREATE_PATH = '/api/ai/contact-sessions/\\d+/widget/messages/create/';

function safeJson(value: unknown): string {
  return JSON.stringify(value).replace(/</g, '\\u003c').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
}

function escapeScriptText(text: string): string {
  return text.replace(/<\/(script)/gi, '<\\/$1').replace(/<!--/g, '<\\!--');
}

const PAGE_PRELUDE = `
(function () {
  var boot = JSON.parse(document.getElementById('blar-boot').textContent);
  try { sessionStorage.setItem('blar_tab_id', boot.tabId); } catch (error) {}

  function post(message) {
    if (window.ReactNativeWebView) window.ReactNativeWebView.postMessage(JSON.stringify(message));
  }
  window.__blarPost = post;

  var pending = {};
  var counter = 0;
  function callNative(name, args) {
    return new Promise(function (resolve, reject) {
      var id = 'c' + (++counter);
      var timer = setTimeout(function () { delete pending[id]; reject(new Error('native call timed out: ' + name)); }, 8000);
      pending[id] = { resolve: resolve, reject: reject, timer: timer };
      post({ kind: 'call', id: id, name: name, args: args || {} });
    });
  }
  window.__blarCallNative = callNative;
  window.__blarNative = {
    resolve: function (id, value, error) {
      var entry = pending[id];
      if (!entry) return;
      clearTimeout(entry.timer);
      delete pending[id];
      if (error) entry.reject(new Error(error)); else entry.resolve(value);
    },
    event: function (name, payload) {
      window.dispatchEvent(new CustomEvent('blar-native', { detail: { name: name, payload: payload } }));
    }
  };

  var nativeFetch = window.fetch.bind(window);
  var messageCreate = new RegExp(boot.messageCreatePath + '$');
  window.fetch = function (input, init) {
    var url = typeof input === 'string' ? input : (input && input.url) || '';
    var method = ((init && init.method) || (input && input.method) || 'GET').toUpperCase();
    if (method !== 'POST' || !messageCreate.test(url.split('?')[0]) || !init || typeof init.body !== 'string') {
      return nativeFetch(input, init);
    }
    return callNative('metadata', { includeTextDom: true }).then(function (metadata) {
      var body = JSON.parse(init.body);
      body.metadata = Object.assign({}, body.metadata || {}, metadata || {});
      return nativeFetch(input, Object.assign({}, init, { body: JSON.stringify(body) }));
    }, function () {
      return nativeFetch(input, init);
    });
  };

  ['error', 'unhandledrejection'].forEach(function (type) {
    window.addEventListener(type, function (event) {
      var reason = type === 'error' ? (event.message || '') : String(event.reason && event.reason.message || event.reason);
      post({ kind: 'log', level: 'error', text: type + ': ' + reason });
    });
  });
})();
`;

const PAGE_START = `
(function () {
  var boot = JSON.parse(document.getElementById('blar-boot').textContent);
  var identity = boot.identity;
  var widgetIdentity = null;
  if (identity) {
    widgetIdentity = {
      externalId: identity.externalId, email: identity.email, name: identity.name, phone: identity.phone,
      contactCompany: identity.contactCompany, contactCompanyExternalId: identity.contactCompanyExternalId,
      customFields: identity.country ? Object.assign({ country: identity.country }, identity.customFields || {}) : identity.customFields,
      identityToken: identity.identityToken, identitySignature: identity.identitySignature
    };
    if (identity.providesProof) {
      widgetIdentity.getProof = function () { return window.__blarCallNative('proof', {}); };
    }
  }
  var config = {
    publishableKey: boot.publishableKey, apiBaseUrl: boot.apiBaseUrl, language: boot.language,
    messagesOnly: true, autoOpen: true, startHidden: true, enableSound: false, showBranding: false,
    agentExecution: false,
    onClose: function () { window.__blarPost({ kind: 'closed' }); },
    onSessionChange: function (sessionId) {
      window.__blarPost({ kind: 'session', sessionId: typeof sessionId === 'number' ? sessionId : null });
    }
  };
  if (boot.primaryColor) config.primaryColor = boot.primaryColor;
  if (widgetIdentity) config.identity = widgetIdentity;
  var widget = window.initSupportWidget(config);
  window.__blarWidget = widget;
  window.addEventListener('blar-native', function (event) {
    var detail = event.detail || {};
    var payload = detail.payload || {};
    if (detail.name === 'open') {
      Promise.resolve(widget.openChat()).catch(function () {});
    } else if (detail.name === 'openSession' && typeof payload.sessionId === 'number') {
      Promise.resolve(widget.openSession(payload.sessionId)).catch(function () {});
    }
  });
  Promise.resolve(widget.openChat()).catch(function () {});
  if (widgetIdentity) {
    Promise.resolve(widget.setUser(widgetIdentity)).catch(function (error) {
      window.__blarPost({ kind: 'log', level: 'error', text: 'setUser failed: ' + (error && error.message) });
    });
  }
  window.__blarPost({ kind: 'ready' });
})();
`;

export function buildWidgetShell(options: WidgetShellOptions): string {
  const boot = {
    publishableKey: options.publishableKey,
    apiBaseUrl: options.apiBaseUrl,
    language: options.language,
    tabId: options.tabId,
    primaryColor: options.primaryColor,
    identity: options.identity,
    messageCreatePath: MESSAGE_CREATE_PATH,
  };
  const widgetScript = options.scriptUrl !== null
    ? `<script src="${options.scriptUrl}"></script>`
    : `<script>${escapeScriptText(options.bundle ?? '')}</script>`;
  return [
    '<!doctype html>',
    '<html><head><meta charset="utf-8">',
    '<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content">',
    '<style>html,body{margin:0;height:100%;background:transparent;overflow:hidden}</style>',
    '</head><body>',
    `<script id="blar-boot" type="application/json">${safeJson(boot)}</script>`,
    `<script>${PAGE_PRELUDE}</script>`,
    widgetScript,
    `<script>${PAGE_START}</script>`,
    '</body></html>',
  ].join('\n');
}

