// NanoPy Oracle - Frontend Application with MetaMask Integration

const API_BASE = window.location.origin;

// ABI encode submitDataString(string keyStr, int256 value, uint256 confidence)
function encodeSubmitDataString(keyStr, value, confidence) {
    // Function selector: keccak256('submitDataString(string,int256,uint256)')[:8]
    const selector = '2e18f176';

    // Encode string: offset (0x60 = 96), then value, then confidence, then string data
    // String is dynamic, so we put offset first
    const stringOffset = '0000000000000000000000000000000000000000000000000000000000000060'; // 96 in hex

    // int256 value (positive number, left-padded)
    const valueHex = value.toString(16).padStart(64, '0');

    // uint256 confidence
    const confidenceHex = confidence.toString(16).padStart(64, '0');

    // String encoding: length + data (padded to 32 bytes)
    const keyBytes = new TextEncoder().encode(keyStr);
    const keyLength = keyBytes.length.toString(16).padStart(64, '0');

    // Pad string data to multiple of 32 bytes
    let keyHex = '';
    for (let i = 0; i < keyBytes.length; i++) {
        keyHex += keyBytes[i].toString(16).padStart(2, '0');
    }
    // Pad to 32 bytes
    while (keyHex.length % 64 !== 0) {
        keyHex += '00';
    }

    return '0x' + selector + stringOffset + valueHex + confidenceHex + keyLength + keyHex;
}
let history = [];
let walletConnected = false;
let userAddress = null;
let lastOracleResponse = null;

// NanoPy Network configuration
const NANOPY_NETWORK = {
    chainId: '0x' + (77777).toString(16), // 77777
    chainName: 'NanoPy Network',  // Different name to avoid MetaMask cache conflict
    nativeCurrency: {
        name: 'NanoPy',
        symbol: 'NPY',
        decimals: 18
    },
    rpcUrls: ['http://51.68.125.99:8546'],
    blockExplorerUrls: ['http://51.68.125.99:8080/explorer']
};

// Oracle contract address (deployed on NanoPy Testnet)
const ORACLE_CONTRACT = '0x059fb0cb87cc646cf4d5206650443cd3d3f34585';

// Oracle contract ABI (for on-chain data submission)
const ORACLE_ABI = [
    {
        "inputs": [
            {"name": "keyStr", "type": "string"},
            {"name": "value", "type": "int256"},
            {"name": "confidence", "type": "uint256"}
        ],
        "name": "submitDataString",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "inputs": [{"name": "keyStr", "type": "string"}],
        "name": "getDataString",
        "outputs": [
            {"name": "value", "type": "int256"},
            {"name": "confidence", "type": "uint256"},
            {"name": "timestamp", "type": "uint256"},
            {"name": "provider", "type": "address"}
        ],
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [{"name": "", "type": "address"}],
        "name": "authorizedOracles",
        "outputs": [{"name": "", "type": "bool"}],
        "stateMutability": "view",
        "type": "function"
    }
];

// Initialize
document.addEventListener('DOMContentLoaded', function() {
    // Update model status on change
    document.getElementById('model-select').addEventListener('change', function() {
        const model = this.value.split('/').pop();
        document.getElementById('model-status').textContent = 'Model: ' + model;
    });

    // Set initial model status
    document.getElementById('model-status').textContent = 'Model: Qwen2.5-0.5B';

    // Allow Enter to submit
    document.getElementById('prompt-input').addEventListener('keydown', function(e) {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            queryOracle();
        }
    });

    // Check if MetaMask is already connected
    checkWalletConnection();

    // Listen for account changes
    if (window.ethereum) {
        window.ethereum.on('accountsChanged', handleAccountsChanged);
        window.ethereum.on('chainChanged', function() {
            window.location.reload();
        });
    }
});

async function checkWalletConnection() {
    if (typeof window.ethereum !== 'undefined') {
        try {
            const accounts = await window.ethereum.request({ method: 'eth_accounts' });
            if (accounts.length > 0) {
                await handleAccountsChanged(accounts);
            }
        } catch (error) {
            console.log('Error checking wallet:', error);
        }
    }
}

async function connectWallet() {
    if (typeof window.ethereum === 'undefined') {
        alert('MetaMask is not installed! Please install MetaMask to use wallet features.');
        window.open('https://metamask.io/download/', '_blank');
        return;
    }

    try {
        // Request account access
        const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
        await handleAccountsChanged(accounts);

        // Try to add NanoPy network
        try {
            await window.ethereum.request({
                method: 'wallet_addEthereumChain',
                params: [NANOPY_NETWORK]
            });
        } catch (addError) {
            console.log('Could not add NanoPy network:', addError);
        }
    } catch (error) {
        if (error.code === 4001) {
            alert('Connection rejected. Please approve the connection in MetaMask.');
        } else {
            console.error('Error connecting wallet:', error);
            alert('Error connecting wallet: ' + error.message);
        }
    }
}

async function handleAccountsChanged(accounts) {
    if (accounts.length === 0) {
        disconnectWallet();
        return;
    }

    userAddress = accounts[0];
    walletConnected = true;

    // Update UI
    document.getElementById('wallet-content').style.display = 'none';
    document.getElementById('wallet-connected').style.display = 'block';
    document.getElementById('wallet-address').textContent = shortenAddress(userAddress);
    document.getElementById('sign-btn').disabled = false;

    // Update status bar
    const statusDot = document.querySelector('#wallet-status .status-dot');
    statusDot.classList.remove('disconnected');
    statusDot.classList.add('connected');
    document.getElementById('wallet-text').textContent = 'Wallet: ' + shortenAddress(userAddress);

    // Get balance directly from NanoPy RPC (not through MetaMask)
    try {
        const response = await fetch(NANOPY_NETWORK.rpcUrls[0], {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                jsonrpc: '2.0',
                method: 'eth_getBalance',
                params: [userAddress, 'latest'],
                id: 1
            })
        });
        const data = await response.json();
        const balance = parseInt(data.result, 16) / 1e18;
        document.getElementById('wallet-balance').textContent = balance.toFixed(4) + ' NPY';
    } catch (error) {
        console.log('Error fetching balance:', error);
        document.getElementById('wallet-balance').textContent = '- NPY';
    }
}

function disconnectWallet() {
    walletConnected = false;
    userAddress = null;

    // Update UI
    document.getElementById('wallet-content').style.display = 'block';
    document.getElementById('wallet-connected').style.display = 'none';
    document.getElementById('sign-btn').disabled = true;

    // Update status bar
    const statusDot = document.querySelector('#wallet-status .status-dot');
    statusDot.classList.remove('connected');
    statusDot.classList.add('disconnected');
    document.getElementById('wallet-text').textContent = 'Wallet: Not Connected';
}

function shortenAddress(address) {
    return address.slice(0, 6) + '...' + address.slice(-4);
}

function setPrompt(text) {
    document.getElementById('prompt-input').value = text;
    document.getElementById('prompt-input').focus();
}

function clearInput() {
    document.getElementById('prompt-input').value = '';
    document.getElementById('prompt-input').focus();
}

async function queryOracle() {
    const prompt = document.getElementById('prompt-input').value.trim();
    if (!prompt) {
        alert('Please enter a prompt');
        return;
    }

    const model = document.getElementById('model-select').value;
    const btn = document.getElementById('query-btn');
    const responseArea = document.getElementById('response-area');
    const responseText = document.getElementById('response-text');

    // Show loading state
    btn.disabled = true;
    btn.innerHTML = '<div class="spinner"></div><span>Querying...</span>';
    responseArea.classList.add('loading');
    responseText.textContent = 'Thinking...';
    responseText.classList.add('placeholder');

    const startTime = Date.now();

    try {
        // Call the oracle API
        const response = await fetch(API_BASE + '/api/oracle/query', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                prompt: prompt,
                model: model,
                max_tokens: 100
            })
        });

        const data = await response.json();
        const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);

        // Store response for signing
        lastOracleResponse = {
            prompt: prompt,
            response: data.response || data.value || 'No response',
            model: model,
            confidence: data.confidence || 90,
            timestamp: Date.now()
        };

        // Update response
        responseText.textContent = lastOracleResponse.response;
        responseText.classList.remove('placeholder');

        // Update metadata
        document.getElementById('metadata').style.display = 'flex';
        document.getElementById('meta-model').textContent = model.split('/').pop();
        document.getElementById('meta-tokens').textContent = data.tokens || data.response_length || '-';
        document.getElementById('meta-time').textContent = elapsed + 's';
        document.getElementById('meta-confidence').textContent = lastOracleResponse.confidence + '%';
        document.getElementById('tx-hash-container').style.display = 'none';

        // Add to history
        addToHistory(prompt, lastOracleResponse.response, model, elapsed);

    } catch (error) {
        // Demo mode - simulate response
        console.log('API not available, using demo mode');
        const demoResponses = {
            'ethereum': 'Ethereum is a decentralized blockchain platform that enables smart contracts and decentralized applications (dApps). It uses Ether (ETH) as its native cryptocurrency.',
            'bitcoin': 'Bitcoin is the first and largest cryptocurrency by market cap. It was created by Satoshi Nakamoto in 2009 as a peer-to-peer electronic cash system.',
            'smart contract': 'A smart contract is a self-executing program stored on a blockchain that automatically enforces the terms of an agreement when predetermined conditions are met.',
            'oracle': 'A blockchain oracle is a service that connects smart contracts with external data sources, enabling them to interact with real-world information.',
            'default': 'The oracle has processed your query. In production, this would connect to the LLM backend for intelligent responses about blockchain, crypto, and more.'
        };

        let response = demoResponses.default;
        for (const [key, value] of Object.entries(demoResponses)) {
            if (prompt.toLowerCase().includes(key)) {
                response = value;
                break;
            }
        }

        const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);

        lastOracleResponse = {
            prompt: prompt,
            response: response,
            model: model,
            confidence: 85,
            timestamp: Date.now()
        };

        responseText.textContent = response;
        responseText.classList.remove('placeholder');

        document.getElementById('metadata').style.display = 'flex';
        document.getElementById('meta-model').textContent = model.split('/').pop() + ' (demo)';
        document.getElementById('meta-tokens').textContent = response.split(' ').length;
        document.getElementById('meta-time').textContent = elapsed + 's';
        document.getElementById('meta-confidence').textContent = '85%';
        document.getElementById('tx-hash-container').style.display = 'none';

        addToHistory(prompt, response, model + ' (demo)', elapsed);
    }

    // Reset button
    btn.disabled = false;
    btn.innerHTML = '<span>Query Oracle</span>';
    responseArea.classList.remove('loading');
}

async function signAndSubmit() {
    if (!walletConnected || !userAddress) {
        alert('Please connect your wallet first');
        return;
    }

    if (!lastOracleResponse) {
        alert('Please query the oracle first');
        return;
    }

    const signBtn = document.getElementById('sign-btn');
    signBtn.disabled = true;
    signBtn.innerHTML = '<div class="spinner"></div><span>Submitting to blockchain...</span>';

    try {
        // First, switch to NanoPy Network
        try {
            await window.ethereum.request({
                method: 'wallet_switchEthereumChain',
                params: [{ chainId: NANOPY_NETWORK.chainId }]
            });
        } catch (switchError) {
            // Network not added yet, add it
            if (switchError.code === 4902) {
                await window.ethereum.request({
                    method: 'wallet_addEthereumChain',
                    params: [NANOPY_NETWORK]
                });
            } else {
                throw switchError;
            }
        }

        // Prepare contract call data
        // submitDataString(string keyStr, int256 value, uint256 confidence)
        const key = 'oracle:' + lastOracleResponse.prompt.slice(0, 32).replace(/[^a-zA-Z0-9]/g, '_');

        // Convert response to a hash/numeric value (use confidence * 10 for now)
        const value = lastOracleResponse.confidence * 10; // Store as int256
        const confidence = lastOracleResponse.confidence * 10; // 0-1000 scale

        // Encode the function call
        const encodedData = encodeSubmitDataString(key, value, confidence);

        console.log('Submitting to Oracle contract:', ORACLE_CONTRACT);
        console.log('Key:', key, 'Value:', value, 'Confidence:', confidence);

        // Send transaction via MetaMask
        const txHash = await window.ethereum.request({
            method: 'eth_sendTransaction',
            params: [{
                from: userAddress,
                to: ORACLE_CONTRACT,
                data: encodedData,
                gas: '0x30000' // 196608 gas
            }]
        });

        console.log('Transaction sent:', txHash);

        // Show transaction hash
        document.getElementById('tx-hash-container').style.display = 'block';
        const txLink = document.getElementById('meta-tx');
        txLink.textContent = shortenAddress(txHash);
        txLink.href = NANOPY_NETWORK.blockExplorerUrls[0] + '/tx/' + txHash;

        alert('Transaction submitted!\n\nTX: ' + txHash);

    } catch (error) {
        if (error.code === 4001) {
            alert('Transaction rejected by user');
        } else {
            console.error('Error signing:', error);
            alert('Error: ' + error.message);
        }
    }

    signBtn.disabled = false;
    signBtn.innerHTML = '<span>Sign & Submit On-Chain</span>';
}

function addToHistory(prompt, response, model, time) {
    history.unshift({ prompt, response, model, time, timestamp: new Date() });

    // Keep only last 10
    if (history.length > 10) history.pop();

    renderHistory();
}

function renderHistory() {
    const list = document.getElementById('history-list');

    if (history.length === 0) {
        list.innerHTML = '<div class="empty-state"><div class="icon">[No History]</div><p>No queries yet. Start by asking the oracle something!</p></div>';
        return;
    }

    list.innerHTML = history.map(function(item) {
        return '<div class="history-item">' +
            '<div class="history-prompt">Q: ' + escapeHtml(item.prompt) + '</div>' +
            '<div class="history-response">' + escapeHtml(item.response) + '</div>' +
            '<div class="history-time">' + item.time + 's - ' + formatTime(item.timestamp) + '</div>' +
        '</div>';
    }).join('');
}

function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

function formatTime(date) {
    return date.toLocaleTimeString();
}

// Reset NanoPy network in MetaMask (switch to mainnet, then re-add NanoPy)
async function resetNetwork() {
    if (typeof window.ethereum === 'undefined') {
        alert('MetaMask is not installed!');
        return;
    }

    try {
        // Step 1: Switch to Ethereum Mainnet first
        alert('Step 1: Switching to Ethereum Mainnet...\nThis will allow you to delete the old NanoPy network.');

        try {
            await window.ethereum.request({
                method: 'wallet_switchEthereumChain',
                params: [{ chainId: '0x1' }] // Ethereum Mainnet
            });
        } catch (switchError) {
            console.log('Could not switch to mainnet:', switchError);
        }

        // Step 2: Instructions for manual deletion
        alert('Step 2: Now go to MetaMask:\n\n' +
              '1. Click the network dropdown (top)\n' +
              '2. Click "Show test networks" or scroll down\n' +
              '3. Find "NanoPy Testnet"\n' +
              '4. Click the 3 dots > Delete\n\n' +
              'Then click OK to add the correct network.');

        // Step 3: Add the correct NanoPy network
        await window.ethereum.request({
            method: 'wallet_addEthereumChain',
            params: [NANOPY_NETWORK]
        });

        alert('NanoPy network added!\n\n' +
              'Chain ID: 77777\n' +
              'RPC: http://51.68.125.99:8546\n' +
              'Symbol: NPY');

        window.location.reload();

    } catch (error) {
        console.error('Error resetting network:', error);
        alert('Error: ' + error.message + '\n\nTry manually deleting the network in MetaMask settings.');
    }
}
