const axios = require('axios');
const { Web3 } = require('web3');
const fs = require('fs');
require('dotenv').config();

// Constants
const CHAINSTACK_API_KEY = process.env.CHAINSTACK_API_KEY;
const OUTPUT_FILE_NAME = 'rpc.env';

// Fetch data from Chainstack API
async function fetchChainstackData(apiKey) {
    const url = "https://api.chainstack.com/v1/nodes/";
    const headers = {
        "accept": "application/json",
        "authorization": `Bearer ${apiKey}`
    };

    try {
        const response = await axios.get(url, { headers });
        console.log(`Fetched ${response.data.results.length} items from Chainstack.`);
        return response.data;
    } catch (error) {
        console.error(`Failed to fetch data from Chainstack: ${error}`);
        return null;
    }
}

// Process a single item from Chainstack data
function processChainstackItem(item) {
    console.debug(`Processing item: ${item.name} with ID ${item.id}`);
    return {
        id: item.id,
        name: item.name,
        details: item.details,
        http_endpoint: item.details.https_endpoint,
        auth_key: item.details.auth_key,
        configuration: item.configuration,
        client: item.configuration.client
    };
}

// Connect to a Web3 endpoint
async function connectToWeb3(reconstructedEndpoint) {
    console.debug(`Attempting to connect to Web3 endpoint: ${reconstructedEndpoint}`);
    try {
        const web3 = new Web3(new Web3.providers.HttpProvider(reconstructedEndpoint));
        const chainId = await web3.eth.getChainId();
        console.info(`Connected to ${reconstructedEndpoint} with chain ID: ${chainId}`);
        return true;
    } catch (error) {
        console.error(`Failed to connect to ${reconstructedEndpoint}: ${error}`);
        return false;
    }
}


// Sanitize the endpoint name for use as an environment variable key
function sanitizeName(name) {
    return name.replace(/\s|-|\//g, "_").toUpperCase();
}

// Create a .env file from the endpoint info dictionary
function createEnvFile(endpointInfoDict, filename = OUTPUT_FILE_NAME) {
    console.info(`Preparing to write ${Object.keys(endpointInfoDict).length} endpoints to .env file.`);
    const lines = Object.entries(endpointInfoDict).map(([endpoint, info]) => {
        const sanitized_name = sanitizeName(info.name);
        return `${sanitized_name}_URL="${endpoint}"\n`;
    });

    fs.writeFileSync(filename, lines.join(''));
    console.info(`.env file created successfully at ${filename}`);
}

// Main function to orchestrate the process
async function main() {
    console.info("Starting main process.");
    if (!CHAINSTACK_API_KEY) {
        console.error("Chainstack API key not found.");
        return;
    }

    const json_data = await fetchChainstackData(CHAINSTACK_API_KEY);
    if (!json_data) {
        return;
    }

    const endpointInfoDict = {};
    for (const item of json_data.results) {
        const data = processChainstackItem(item);
        const reconstructedEndpoint = `${data.http_endpoint}/${data.auth_key}`;
        if (await connectToWeb3(reconstructedEndpoint)) {
            endpointInfoDict[reconstructedEndpoint] = { name: data.name };
        }
    }

    if (Object.keys(endpointInfoDict).length > 0) {
        createEnvFile(endpointInfoDict);
    } else {
        console.info("No endpoint information to write to .env file.");
    }
    console.info("Main process completed.");
}

// Run the main function
main();
Starting main process.
Fetched 10 items from Chainstack.
Processing item: Eth mainnet with ID ND-422-757-666
Attempting to connect to Web3 endpoint: https://nd-422-757-666.p2pify.com/
Connected to https://nd-422-757-666.p2pify.com/ with chain ID: 1
Processing item: Poly mainnet with ID ND-828-700-214
Attempting to connect to Web3 endpoint: https://nd-828-700-214.p2pify.com/
Connected to https://nd-828-700-214.p2pify.com/ with chain ID: 137
Processing item: Ava mainnet with ID ND-418-459-126
Attempting to connect to Web3 endpoint: https://nd-418-459-126.p2pify.com/
Failed to connect to https://nd-418-459-126.p2pify.com/: ResponseError: Returned error: Internal error
Processing item: Arb mainnet with ID ND-000-364-211
Attempting to connect to Web3 endpoint: https://nd-000-364-211.p2pify.com/
Connected to https://nd-000-364-211.p2pify.com/ with chain ID: 42161
Processing item: Sol mainnet with ID ND-326-444-187
Attempting to connect to Web3 endpoint: https://nd-326-444-187.p2pify.com/
Failed to connect to https://nd-326-444-187.p2pify.com/: InvalidResponseError: Returned error: Method not found
Processing item: Gno mainnet with ID ND-500-249-268
Attempting to connect to Web3 endpoint: https://nd-500-249-268.p2pify.com/
Connected to https://nd-500-249-268.p2pify.com/ with chain ID: 100
Processing item: Node-1 with ID ND-363-550-219
Attempting to connect to Web3 endpoint: https://nd-363-550-219.p2pify.com/
Connected to https://nd-363-550-219.p2pify.com/ with chain ID: 1101
Processing item: Arb mainnet with debug/trace with ID ND-954-882-037
Attempting to connect to Web3 endpoint: https://nd-954-882-037.p2pify.com/
Connected to https://nd-954-882-037.p2pify.com/ with chain ID: 42161
Processing item: Starknet Mainnet with ID ND-097-590-908
Attempting to connect to Web3 endpoint: https://starknet-mainnet.core.chainstack.com/
Failed to connect to https://starknet-mainnet.core.chainstack.com/: InvalidResponseError: Returned error: Method not found
Processing item: getTokenAccountsByDelegate with ID ND-106-833-045
Attempting to connect to Web3 endpoint: https://nd-106-833-045.p2pify.com/
Failed to connect to https://nd-106-833-045.p2pify.com/: InvalidResponseError: Returned error: Method not found
Preparing to write 6 endpoints to .env file.
.env file created successfully at rpc.env
Main process completed.
const axios = require('axios');
const { Web3 } = require('web3');
const fs = require('fs');
require('dotenv').config();

// Constants
const CHAINSTACK_API_KEY = process.env.CHAINSTACK_API_KEY;
const OUTPUT_FILE_NAME = 'rpc.env';

// Fetch data from Chainstack API
async function fetchChainstackData(apiKey) {
    const url = "https://api.chainstack.com/v1/nodes/";
    const headers = {
        "accept": "application/json",
        "authorization": `Bearer ${apiKey}`
    };

    try {
        const response = await axios.get(url, { headers });
        console.log(`Fetched ${response.data.results.length} items from Chainstack.`);
        return response.data;
    } catch (error) {
        console.error(`Failed to fetch data from Chainstack: ${error}`);
        return null;
    }
}

// Process a single item from Chainstack data
function processChainstackItem(item) {
    console.debug(`Processing item: ${item.name} with ID ${item.id}`);
    return {
        id: item.id,
        name: item.name,
        details: item.details,
        http_endpoint: item.details.https_endpoint,
        auth_key: item.details.auth_key,
        configuration: item.configuration,
        client: item.configuration.client
    };
}

// Connect to a Web3 endpoint
async function connectToWeb3(reconstructedEndpoint) {
    console.debug(`Attempting to connect to Web3 endpoint: ${reconstructedEndpoint}`);
    try {
        const web3 = new Web3(new Web3.providers.HttpProvider(reconstructedEndpoint));
        const chainId = await web3.eth.getChainId();
        console.info(`Connected to ${reconstructedEndpoint} with chain ID: ${chainId}`);
        return true;
    } catch (error) {
        console.error(`Failed to connect to ${reconstructedEndpoint}: ${error}`);
        return false;
    }
}


// Sanitize the endpoint name for use as an environment variable key
function sanitizeName(name) {
    return name.replace(/\s|-|\//g, "_").toUpperCase();
}

// Create a .env file from the endpoint info dictionary
function createEnvFile(endpointInfoDict, filename = OUTPUT_FILE_NAME) {
    console.info(`Preparing to write ${Object.keys(endpointInfoDict).length} endpoints to .env file.`);
    const lines = Object.entries(endpointInfoDict).map(([endpoint, info]) => {
        const sanitized_name = sanitizeName(info.name);
        return `${sanitized_name}_URL="${endpoint}"\n`;
    });

    fs.writeFileSync(filename, lines.join(''));
    console.info(`.env file created successfully at ${filename}`);
}

// Main function to orchestrate the process
async function main() {
    console.info("Starting main process.");
    if (!CHAINSTACK_API_KEY) {
        console.error("Chainstack API key not found.");
        return;
    }

    const json_data = await fetchChainstackData(CHAINSTACK_API_KEY);
    if (!json_data) {
        return;
    }

    const endpointInfoDict = {};
    for (const item of json_data.results) {
        const data = processChainstackItem(item);
        const reconstructedEndpoint = `${data.http_endpoint}/${data.auth_key}`;
        if (await connectToWeb3(reconstructedEndpoint)) {
            endpointInfoDict[reconstructedEndpoint] = { name: data.name };
        }
    }

    if (Object.keys(endpointInfoDict).length > 0) {
        createEnvFile(endpointInfoDict);
    } else {
        console.info("No endpoint information to write to .env file.");
    }
    console.info("Main process completed.");
}

// Run the main function
main();
Starting main process.
Fetched 10 items from Chainstack.
Processing item: Eth mainnet with ID ND-422-757-666
Attempting to connect to Web3 endpoint: https://nd-422-757-666.p2pify.com/
Connected to https://nd-422-757-666.p2pify.com/ with chain ID: 1
Processing item: Poly mainnet with ID ND-828-700-214
Attempting to connect to Web3 endpoint: https://nd-828-700-214.p2pify.com/
Connected to https://nd-828-700-214.p2pify.com/ with chain ID: 137
Processing item: Ava mainnet with ID ND-418-459-126
Attempting to connect to Web3 endpoint: https://nd-418-459-126.p2pify.com/
Failed to connect to https://nd-418-459-126.p2pify.com/: ResponseError: Returned error: Internal error
Processing item: Arb mainnet with ID ND-000-364-211
Attempting to connect to Web3 endpoint: https://nd-000-364-211.p2pify.com/
Connected to https://nd-000-364-211.p2pify.com/ with chain ID: 42161
Processing item: Sol mainnet with ID ND-326-444-187
Attempting to connect to Web3 endpoint: https://nd-326-444-187.p2pify.com/
Failed to connect to https://nd-326-444-187.p2pify.com/: InvalidResponseError: Returned error: Method not found
Processing item: Gno mainnet with ID ND-500-249-268
Attempting to connect to Web3 endpoint: https://nd-500-249-268.p2pify.com/
Connected to https://nd-500-249-268.p2pify.com/ with chain ID: 100
Processing item: Node-1 with ID ND-363-550-219
Attempting to connect to Web3 endpoint: https://nd-363-550-219.p2pify.com/
Connected to https://nd-363-550-219.p2pify.com/ with chain ID: 1101
Processing item: Arb mainnet with debug/trace with ID ND-954-882-037
Attempting to connect to Web3 endpoint: https://nd-954-882-037.p2pify.com/
Connected to https://nd-954-882-037.p2pify.com/ with chain ID: 42161
Processing item: Starknet Mainnet with ID ND-097-590-908
Attempting to connect to Web3 endpoint: https://starknet-mainnet.core.chainstack.com/
Failed to connect to https://starknet-mainnet.core.chainstack.com/: InvalidResponseError: Returned error: Method not found
Processing item: getTokenAccountsByDelegate with ID ND-106-833-045
Attempting to connect to Web3 endpoint: https://nd-106-833-045.p2pify.com/
Failed to connect to https://nd-106-833-045.p2pify.com/: InvalidResponseError: Returned error: Method not found
Preparing to write 6 endpoints to .env file.
.env file created successfully at rpc.env
Main process completed.