/**
 * background.js - Extension service worker
 *
 * Handles NFT ownership verification and message routing.
 *
 * ARCHITECTURE NOTE:
 * The dapp (dapp.html/dapp.js) is hosted on Vercel, not in the extension.
 * Messages from the dapp come through dapp_content_script.js (injected into the page).
 * When sending messages back, we use chrome.tabs.sendMessage to the sender's tab ID.
 */

const NFT_CONTRACT_ADDRESS = '0x272160c188f5616f3e2c8dd0c8223c16156f025d';
const ARBITRUM_MAINNET_CHAIN_ID = 42161;
const ETHERSCAN_API_KEY = '6HXX4B8SRPPPM5QVTDUW8BUIWXN639945Z';

// Helper function to send message to a specific tab (used for Vercel-hosted dapp)
function sendMessageToTab(tabId, message) {
  if (tabId) {
    console.log('[Background] Sending message to tab:', tabId, message);
    chrome.tabs.sendMessage(tabId, message).catch(err => {
      console.warn('[Background] Could not send message to tab:', err.message);
    });
  }
}



async function checkNftOwnership(account, chainId) {
  console.log(`[Background] checkNftOwnership called for account: ${account}, chainId: ${chainId}`);
  if (chainId !== ARBITRUM_MAINNET_CHAIN_ID) {
    console.log(`[Background] NFT ownership check skipped: Not on Arbitrum Mainnet (current chainId: ${chainId}).`);
    await chrome.storage.sync.set({ unlockedCharacters: { 'shimeji': true } }); // Lock other characters if not on correct chain
    return;
  }

  // Use public Arbitrum RPC to call balanceOf directly on the NFT contract (FREE, no API key needed)
  const ARBITRUM_RPC = 'https://arb1.arbitrum.io/rpc';

  // ERC-721 balanceOf(address) function selector: 0x70a08231
  const BALANCE_OF_SELECTOR = '0x70a08231';
  // Pad address to 32 bytes (remove 0x prefix, pad to 64 chars)
  const paddedAddress = account.slice(2).toLowerCase().padStart(64, '0');
  const callData = BALANCE_OF_SELECTOR + paddedAddress;

  console.log(`[Background] Calling balanceOf on contract ${NFT_CONTRACT_ADDRESS} for ${account}`);

  try {
    const response = await fetch(ARBITRUM_RPC, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'eth_call',
        params: [{
          to: NFT_CONTRACT_ADDRESS,
          data: callData
        }, 'latest'],
        id: 1
      })
    });

    const data = await response.json();
    console.log("[Background] RPC response:", data);

    let isOwner = false;
    if (data.result && data.result !== '0x') {
      // Parse hex balance - result is a 32-byte hex number
      const balance = parseInt(data.result, 16);
      console.log(`[Background] NFT balance: ${balance}`);
      isOwner = balance > 0;
    } else if (data.error) {
      console.error('[Background] RPC error:', data.error);
    }

    let unlockedCharacters = { 'shimeji': true }; // Shimeji always unlocked
    if (isOwner) {
      unlockedCharacters['icecream'] = true;
      console.log(`[Background] NFTs owned by ${account} on Arbitrum. 'icecream' character unlocked.`);
    } else {
      console.log(`[Background] No NFTs owned by ${account} on Arbitrum. 'icecream' character remains locked.`);
    }
    console.log(`[Background] Storing unlockedCharacters:`, unlockedCharacters);
    await chrome.storage.sync.set({ unlockedCharacters });

  } catch (error) {
    console.error('[Background] Failed to check NFT ownership:', error);
    await chrome.storage.sync.set({ unlockedCharacters: { 'shimeji': true } });
  }
}

chrome.runtime.onInstalled.addListener(() => {
  // Initially set shimeji as default character
  console.log('[Background] Extension installed, setting initial storage values.');
  chrome.storage.sync.set({
    character: 'shimeji',
    behavior: 'wander', // Default to wander mode
    size: 'medium', // Set default size
    unlockedCharacters: { 'shimeji': true }, // Shimeji unlocked by default
    isConnected: false,
    connectedAddress: null,
    disabledAll: false,
    disabledPages: []
  });
});

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
  if (changeInfo.status === 'complete' && tab.url && tab.url.startsWith('http')) {
    chrome.tabs.sendMessage(tabId, { action: 'ping' }, (response) => {
      if (chrome.runtime.lastError || !response?.pong) {
        chrome.scripting.executeScript({
          target: { tabId: tabId },
          files: ['content.js']
        }, () => {
            if (chrome.runtime.lastError) {
                console.error(`[Background] Script injection failed: ${chrome.runtime.lastError.message}`);
            }
          });
      }
    });
  }
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  const senderTabId = sender.tab?.id;

  if (request.type === 'walletConnected') {
    console.log('[Background] Received walletConnected message:', request.payload, 'from tab:', senderTabId);
    chrome.storage.sync.set({
      isConnected: true,
      connectedAddress: request.payload.account,
      connectedChainId: request.payload.chainId
    }, async () => {
      await checkNftOwnership(request.payload.account, request.payload.chainId);
      // After NFT check, get the latest unlockedCharacters from storage
      chrome.storage.sync.get('unlockedCharacters', (data) => {
        console.log('[Background] Sending updateUnlockedCharacters after walletConnected. Payload:', data.unlockedCharacters);
        // Send to the tab that sent the message
        sendMessageToTab(senderTabId, { type: 'EXTENSION_MESSAGE', payload: { type: 'updateUnlockedCharacters', payload: data.unlockedCharacters } });
      });
    });
    sendResponse({ status: 'Wallet connection received' });
    return true;
  } else if (request.type === 'walletDisconnected') {
    console.log('[Background] Received walletDisconnected message from tab:', senderTabId);
    chrome.storage.sync.set({
      isConnected: false,
      connectedAddress: null,
      connectedChainId: null,
      unlockedCharacters: { 'shimeji': true } // Only shimeji unlocked on disconnect
    }, () => { // Add callback to ensure storage is set before sending message
      console.log('[Background] Sending updateUnlockedCharacters after walletDisconnected. Payload: {shimeji: true}');
      // Send to the tab that sent the message
      sendMessageToTab(senderTabId, { type: 'EXTENSION_MESSAGE', payload: { type: 'updateUnlockedCharacters', payload: { 'shimeji': true } } });
    });
    sendResponse({ status: 'Wallet disconnection received' });
    return true;
  } else if (request.type === 'revokePermissionsRequest') {
    console.log('[Background] Revoke permissions request received from tab:', senderTabId);
    chrome.storage.sync.set({
      isConnected: false,
      connectedAddress: null,
      connectedChainId: null,
      unlockedCharacters: { 'shimeji': true }
    }, () => {
      sendMessageToTab(senderTabId, { type: 'EXTENSION_MESSAGE', payload: { type: 'revokePermissionsFromBackground' } });
    });
    sendResponse({ status: 'Permissions revoked' });
    return true;
  } else if (request.type === 'setCharacter') {
    console.log('[Background] Received setCharacter message:', request.payload);
    chrome.storage.sync.set({ character: request.payload.character }, () => {
      chrome.tabs.query({}, (tabs) => {
        tabs.forEach(tab => {
          if(tab.id) {
            chrome.tabs.sendMessage(tab.id, { action: 'updateCharacter', character: request.payload.character })
              .catch(error => {
                if (error.message.includes("Could not establish connection. Receiving end does not exist.")) {
                  // This is expected if content script is not injected in a tab
                  console.warn(`[Background] Failed to send updateCharacter to tab ${tab.id}: No receiving end.`);
                } else {
                  console.error(`[Background] Error sending updateCharacter to tab ${tab.id}:`, error);
                }
              });
          }
        });
      });
      sendResponse({ status: 'Character set' });
    });
    return true;
  } else if (request.type === 'getCharacter') {
    console.log('[Background] Received getCharacter message.');
    chrome.storage.sync.get('character', (data) => {
      console.log('[Background] Sending character:', data.character);
      sendResponse({ type: 'EXTENSION_RESPONSE', payload: { character: data.character } });
    });
    return true;
  } else if (request.type === 'setBehavior') {
    console.log('[Background] Received setBehavior message:', request.payload);
    chrome.storage.sync.set({ behavior: request.payload.behavior }, () => {
      chrome.tabs.query({}, (tabs) => {
        tabs.forEach(tab => {
          if (tab.id) {
            chrome.tabs.sendMessage(tab.id, { action: 'updateBehavior', behavior: request.payload.behavior })
              .catch(error => {
                if (error.message.includes("Could not establish connection. Receiving end does not exist.")) {
                  console.warn(`[Background] Failed to send updateBehavior to tab ${tab.id}: No receiving end.`);
                } else {
                  console.error(`[Background] Error sending updateBehavior to tab ${tab.id}:`, error);
                }
              });
          }
        });
      });
      sendResponse({ status: 'Behavior set' });
    });
    return true;
  } else if (request.type === 'getBehavior') {
    console.log('[Background] Received getBehavior message.');
    chrome.storage.sync.get('behavior', (data) => {
      console.log('[Background] Sending behavior:', data.behavior);
      sendResponse({ behavior: data.behavior });
    });
    return true;
  } else if (request.type === 'setSize') {
    console.log('[Background] Received setSize message:', request.payload);
    chrome.storage.sync.set({ size: request.payload.size }, () => {
      chrome.tabs.query({}, (tabs) => {
        tabs.forEach(tab => {
          if (tab.id) {
            chrome.tabs.sendMessage(tab.id, { action: 'updateSize', size: request.payload.size })
              .catch(error => {
                if (error.message.includes("Could not establish connection. Receiving end does not exist.")) {
                  console.warn(`[Background] Failed to send updateSize to tab ${tab.id}: No receiving end.`);
                } else {
                  console.error(`[Background] Error sending updateSize to tab ${tab.id}:`, error);
                }
              });
          }
        });
      });
      sendResponse({ status: 'Size set' });
    });
    return true;
  } else if (request.type === 'getSize') {
    console.log('[Background] Received getSize message.');
    chrome.storage.sync.get('size', (data) => {
      console.log('[Background] Sending size:', data.size);
      sendResponse({ size: data.size });
    });
    return true;
  } else if (request.type === 'getUnlockedCharacters') {
    console.log('[Background] Received getUnlockedCharacters message.');
    chrome.storage.sync.get(['unlockedCharacters', 'isConnected', 'connectedAddress', 'connectedChainId'], async (data) => {
      console.log('[Background] getUnlockedCharacters - current storage data:', data);
      if (data.isConnected && data.connectedAddress && data.connectedChainId) {
        // If connected, re-check NFT ownership to ensure up-to-date status
        await checkNftOwnership(data.connectedAddress, data.connectedChainId);
        // Fetch updated unlockedCharacters from storage after re-check
        chrome.storage.sync.get('unlockedCharacters', (updatedData) => {
          console.log('[Background] getUnlockedCharacters - sending updated payload:', updatedData.unlockedCharacters);
          sendResponse({ type: 'EXTENSION_RESPONSE', payload: updatedData.unlockedCharacters || {} });
        });
      } else {
        // If not connected, send current (or default) unlockedCharacters
        const payload = data.unlockedCharacters || { 'shimeji': true };
        console.log('[Background] getUnlockedCharacters - not connected, sending payload:', payload);
        sendResponse({ type: 'EXTENSION_RESPONSE', payload: payload });
      }
    });
    return true; // Indicate that sendResponse will be called asynchronously
  } else if (request.type === 'updateUnlockedCharacters') {
    // This message is sent from background to content/dapp. Not handled by background.
    console.warn('[Background] Unexpected: Received updateUnlockedCharacters message from DApp. This should only be sent from background to DApp.');
    sendResponse({ status: 'UpdateUnlockedCharacters message from background (unexpectedly received)' });
    return true;
  }
});