const path = require("path");
require("dotenv").config({ path: path.resolve(__dirname, "../.env") });

const express = require("express");
const axios = require("axios");
const cron = require("node-cron");
const { createClient } = require("@supabase/supabase-js");

// Setup
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY);
const app = express();
app.use(express.json());
// Setup end

// Fetch transactions from Solscan
const fetchSolscanTransactions = async (page = 1) => {
    const requestOptions = {
        method: "get",
        url: "https://pro-api.solscan.io/v2.0/token/transfer",
        params: {
            address: process.env.TOKEN_ADDRESS,
            page,
            page_size: "100",
            sort_by: "block_time",
            sort_order: "desc",
        },
        headers: {
            token: process.env.SOLSCAN_API_KEY,
        },
    };

    try {
        const response = await axios.request(requestOptions);
        return response.data;
    } catch (err) {
        console.error("Error fetching transactions:", err.response ? err.response.data : err.message);
        return [];
    }
};
// Fetch transactions from Solscan end

// Star name generator
const prefixes = [
    "Ar",
    "Zor",
    "Lys",
    "Fen",
    "Ther",
    "Vor",
    "Nyr",
    "Xel",
    "Pry",
    "Kor",
    "Vel",
    "Jal",
    "Mor",
    "Quor",
    "Sy",
    "Ky",
    "Tor",
    "Or",
    "Phor",
    "Zyn",
    "Aly",
    "Sol",
    "Dray",
    "Hal",
    "Lyn",
    "Myr",
    "Zan",
    "Tyr",
    "Val",
    "Xyn",
    "Ner",
    "Cal",
    "Gal",
    "Bry",
    "Cyr",
    "Thal",
    "Aer",
    "Vey",
    "Kry",
    "Nor",
    "Lor",
    "Ael",
    "Bro",
    "Ceth",
    "Fer",
    "Ivor",
    "Jul",
    "Kael",
    "Mal",
    "Oth",
    "Phel",
    "Reva",
    "Syth",
    "Ul",
    "Varn",
    "Wren",
    "Xyl",
    "Yel",
    "Zira",
    "Xor",
    "Arak",
    "Tyl",
    "Yor",
];
const middles = [
    "va",
    "the",
    "ly",
    "na",
    "ri",
    "lo",
    "thra",
    "ven",
    "dra",
    "ny",
    "la",
    "sha",
    "nel",
    "vi",
    "nor",
    "var",
    "sel",
    "yn",
    "ar",
    "ros",
    "mar",
    "car",
    "mel",
    "tre",
    "bre",
    "lin",
    "fae",
    "phy",
    "ran",
    "lys",
    "thar",
    "rae",
    "dal",
    "lor",
    "mer",
    "vin",
    "pol",
    "brey",
    "xan",
    "myl",
    "tor",
    "que",
    "zil",
    "wry",
    "farn",
    "pyr",
    "teth",
    "vyl",
    "andor",
    "selan",
    "ord",
    "ser",
    "cral",
    "zoth",
    "bel",
    "quol",
    "rian",
    "ber",
    "myth",
    "fyl",
    "tain",
    "os",
    "roan",
    "dril",
];
const suffixes = [
    "nis",
    "lon",
    "ris",
    "thon",
    "eth",
    "ion",
    "lis",
    "tis",
    "on",
    "is",
    "ar",
    "os",
    "el",
    "ra",
    "in",
    "us",
    "ae",
    "ys",
    "al",
    "vin",
    "dor",
    "tha",
    "lor",
    "ven",
    "dra",
    "nor",
    "cal",
    "vor",
    "xan",
    "tur",
    "sel",
    "ren",
    "elis",
    "queth",
    "tyl",
    "noris",
    "myra",
    "far",
    "qan",
    "cyr",
    "oris",
    "ythra",
    "xanor",
    "soris",
    "zalor",
    "fenal",
    "arith",
    "zyl",
    "vhen",
    "qeth",
    "anthor",
    "ryl",
    "maris",
    "quen",
    "shon",
    "ghal",
    "valis",
    "thyros",
    "menor",
    "xiros",
];
const generateStarName = async () => {
    const prefix = prefixes[Math.floor(Math.random() * prefixes.length)];
    const middle = middles[Math.floor(Math.random() * middles.length)];
    const suffix = suffixes[Math.floor(Math.random() * suffixes.length)];
    let starName = `${prefix}${middle}${suffix}`;

    // Check if starName already exists in the database
    const { data } = await supabase.from("celestia-data").select("star_name").eq("star_name", starName);

    if (data.length > 0) {
        let counter = 1;
        while (true) {
            const newStarName = `${starName}${counter}`;
            const { data: checkData } = await supabase
                .from("celestia-data")
                .select("star_name")
                .eq("star_name", newStarName);

            if (checkData.length === 0) {
                starName = newStarName;
                break;
            }
            counter++;
        }
    }

    return starName;
};
// Star name generator end

// Store transaction to Supabase
const storeTransactionToSupabase = async (transaction) => {
    const starName = await generateStarName();
    const { trans_id, from_address, amount } = transaction;
    const x = Math.floor(Math.random() * 11) - 5;
    const y = Math.floor(Math.random() * 11) - 5;
    const z = Math.floor(Math.random() * 11) - 5;

    const { count, error: countError } = await supabase
        .from("celestia-data")
        .select("*", { count: "exact", head: true });

    if (countError) {
        console.error("Error counting rows:", countError);
        return;
    }

    const transaction_id = count + 1;

    const { data, error } = await supabase.from("celestia-data").insert([
        {
            transaction_signature: trans_id,
            from_address: from_address,
            amount: amount,
            star_name: starName,
            transaction_id: transaction_id,
            transaction_url: `https://solscan.io/tx/${trans_id}`,
            x: x,
            y: y,
            z: z,
        },
    ]);

    if (error) {
        console.error("Error inserting transaction:", error);
    } else {
        console.log("Transaction added:", data);
    }
};
// Store transaction to Supabase end

// Cron job
let isProcessing = false;

// Cron job to run every 1 minute
cron.schedule("*/1 * * * *", async () => {
    if (isProcessing) {
        console.log("Previous process still running, skipping this iteration");
        return;
    }

    isProcessing = true;
    console.log("Cron job triggered");

    try {
        const { data: latestRow } = await supabase
            .from("celestia-data")
            .select("transaction_signature")
            .order("id", { ascending: false })
            .limit(1);

        const latestTransactionSignature = latestRow.length > 0 ? latestRow[0].transaction_signature : "";

        let page = 1;
        let foundExistingTransaction = false;

        while (!foundExistingTransaction) {
            const transactions = await fetchSolscanTransactions(page);
            if (transactions.length === 0) {
                console.log("No transactions found on page", page);
                break;
            }

            for (let transaction of transactions.data) {
                if (transaction.trans_id !== latestTransactionSignature) {
                    await storeTransactionToSupabase(transaction);
                } else {
                    console.log("Transaction already exists:", transaction.trans_id);
                    foundExistingTransaction = true;
                    break;
                }
            }

            if (!foundExistingTransaction) {
                page++;
            }
        }
    } catch (error) {
        console.error("Error during cron job execution:", error.message);
        console.error(error.stack);
    } finally {
        isProcessing = false;
    }
});
// Cron job end

// Start server
app.listen(3001, () => {
    console.log("Server running on port 3001");
});
// Start server end