/**
 * Canton Wallet Provider — loadable by external dApps
 *
 * Usage: <script src="http://localhost:3000/canton-wallet-provider.js"></script>
 * Sets window.cantonWallet with the full API for cross-origin dApps.
 */
(function () {
  'use strict';

  if (window.cantonWallet) return;

  var WALLET_ORIGIN = new URL(document.currentScript.src).origin;
  var API_BASE = WALLET_ORIGIN.replace(/:\d+$/, ':5100'); // backend API
  var CONNECTIONS_KEY = 'canton_wallet_dapp_connections';
  var VERSION = '1.0.0';

  // ── Connection storage (dApp-side) ──────────────────────────────────

  function loadConnection() {
    try {
      var raw = localStorage.getItem(CONNECTIONS_KEY);
      if (raw) {
        var conns = JSON.parse(raw);
        return conns[WALLET_ORIGIN] || null;
      }
    } catch (e) { /* ignore */ }
    return null;
  }

  function saveConnection(conn) {
    var conns = {};
    try {
      var raw = localStorage.getItem(CONNECTIONS_KEY);
      if (raw) conns = JSON.parse(raw);
    } catch (e) { /* ignore */ }
    conns[WALLET_ORIGIN] = conn;
    localStorage.setItem(CONNECTIONS_KEY, JSON.stringify(conns));
  }

  function clearConnection() {
    var conns = {};
    try {
      var raw = localStorage.getItem(CONNECTIONS_KEY);
      if (raw) conns = JSON.parse(raw);
    } catch (e) { /* ignore */ }
    delete conns[WALLET_ORIGIN];
    localStorage.setItem(CONNECTIONS_KEY, JSON.stringify(conns));
  }

  // ── Event emitter ──────────────────────────────────────────────────

  var listeners = {
    accountChanged: [],
    disconnect: []
  };

  function emit(event, data) {
    var handlers = listeners[event] || [];
    for (var i = 0; i < handlers.length; i++) {
      try { handlers[i](data); } catch (e) { /* swallow */ }
    }
  }

  // ── Connect popup ──────────────────────────────────────────────────

  function openConnectPopup(options) {
    return new Promise(function (resolve, reject) {
      var permissions = (options.requestedPermissions || ['read']).join(',');
      var params = new URLSearchParams({
        origin: window.location.origin,
        name: options.dappName || window.location.origin,
        permissions: permissions
      });
      if (options.dappIcon) {
        params.set('icon', options.dappIcon);
      }

      var width = 420;
      var height = 580;
      var left = Math.round(window.screenX + (window.outerWidth - width) / 2);
      var top = Math.round(window.screenY + (window.outerHeight - height) / 2);

      var popup = window.open(
        WALLET_ORIGIN + '/wallet/connect?' + params.toString(),
        'canton-wallet-connect',
        'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',popup=true'
      );

      if (!popup) {
        reject(new Error('Failed to open connect popup. Please allow popups for this site.'));
        return;
      }

      function handleMessage(event) {
        if (event.origin !== WALLET_ORIGIN) return;
        var data = event.data;
        if (data.type !== 'canton-wallet-connect-response') return;

        window.removeEventListener('message', handleMessage);
        clearInterval(pollInterval);

        if (data.approved && data.partyId && data.displayName && data.publicKey && data.permissions) {
          var result = {
            partyId: data.partyId,
            displayName: data.displayName,
            publicKey: data.publicKey,
            permissions: data.permissions
          };
          saveConnection(result);
          resolve(result);
        } else {
          reject(new Error('Connection rejected by user'));
        }
      }

      window.addEventListener('message', handleMessage);

      var pollInterval = setInterval(function () {
        if (popup.closed) {
          clearInterval(pollInterval);
          window.removeEventListener('message', handleMessage);
          reject(new Error('Connection popup was closed'));
        }
      }, 500);
    });
  }

  // ── Sign popup ────────────────────────────────────────────────────

  function openSignPopup(transaction) {
    var conn = loadConnection();
    return new Promise(function (resolve, reject) {
      var params = new URLSearchParams({
        origin: window.location.origin,
        name: window.location.origin
      });

      var width = 420;
      var height = 620;
      var left = Math.round(window.screenX + (window.outerWidth - width) / 2);
      var top = Math.round(window.screenY + (window.outerHeight - height) / 2);

      var popup = window.open(
        WALLET_ORIGIN + '/wallet/connect/sign?' + params.toString(),
        'canton-wallet-sign',
        'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',popup=true'
      );

      if (!popup) {
        reject(new Error('Failed to open sign popup. Please allow popups for this site.'));
        return;
      }

      function handleMessage(event) {
        if (event.origin !== WALLET_ORIGIN) return;
        var data = event.data;

        if (data.type === 'canton-wallet-sign-ready') {
          popup.postMessage({
            type: 'canton-wallet-sign-request',
            transaction: transaction,
            origin: window.location.origin,
            dappName: window.location.origin
          }, WALLET_ORIGIN);
          return;
        }

        if (data.type !== 'canton-wallet-sign-response') return;

        window.removeEventListener('message', handleMessage);
        clearInterval(pollInterval);

        if (data.approved && data.transactionId) {
          resolve({ transactionId: data.transactionId });
        } else {
          reject(new Error('User rejected the transaction'));
        }
      }

      window.addEventListener('message', handleMessage);

      var pollInterval = setInterval(function () {
        if (popup.closed) {
          clearInterval(pollInterval);
          window.removeEventListener('message', handleMessage);
          reject(new Error('Sign popup was closed'));
        }
      }, 500);
    });
  }

  // ── Account change polling ─────────────────────────────────────────

  var lastPartyId = null;

  function startAccountWatcher() {
    var conn = loadConnection();
    lastPartyId = conn ? conn.partyId : null;

    // Listen for disconnect events from the wallet settings page (revoke)
    window.addEventListener('storage', function (e) {
      if (e.key === CONNECTIONS_KEY) {
        var current = loadConnection();
        if (!current && lastPartyId) {
          lastPartyId = null;
          emit('disconnect');
        } else if (current && current.partyId !== lastPartyId) {
          lastPartyId = current.partyId;
          emit('accountChanged', current.partyId);
        }
      }
    });
  }

  // ── API ──────────────────────────────────────────────────────────────

  window.cantonWallet = {
    isCantonWallet: true,
    version: VERSION,

    connect: function (options) {
      options = options || {};
      var existing = loadConnection();
      if (existing) {
        return Promise.resolve(existing);
      }
      return openConnectPopup(options);
    },

    disconnect: function () {
      clearConnection();
      emit('disconnect');
    },

    isConnected: function () {
      return loadConnection() !== null;
    },

    getPartyId: function () {
      var conn = loadConnection();
      if (!conn) return Promise.reject(new Error('Not connected. Call connect() first.'));
      return Promise.resolve(conn.partyId);
    },

    getBalances: function () {
      var conn = loadConnection();
      if (!conn) return Promise.reject(new Error('Not connected. Call connect() first.'));
      if (conn.permissions && conn.permissions.indexOf('read') === -1) {
        return Promise.reject(new Error('Read permission not granted'));
      }
      return fetch(API_BASE + '/balances/' + encodeURIComponent(conn.partyId), {
        headers: { 'Content-Type': 'application/json' }
      })
        .then(function (res) {
          if (!res.ok) throw new Error('Failed to fetch balances');
          return res.json();
        })
        .then(function (data) {
          return (data.balances || []).map(function (b) {
            return { symbol: b.symbol, amount: b.amount };
          });
        });
    },

    signAndSubmit: function (tx) {
      var conn = loadConnection();
      if (!conn) return Promise.reject(new Error('Not connected. Call connect() first.'));
      if (conn.permissions && conn.permissions.indexOf('sign') === -1) {
        return Promise.reject(new Error('Sign permission not granted'));
      }
      return openSignPopup(tx);
    },

    on: function (event, handler) {
      if (listeners[event]) listeners[event].push(handler);
    },

    off: function (event, handler) {
      if (!listeners[event]) return;
      var idx = listeners[event].indexOf(handler);
      if (idx !== -1) listeners[event].splice(idx, 1);
    }
  };

  startAccountWatcher();
})();
