import express from 'express';
import { LAMPORTS_PER_SOL, clusterApiUrl } from "@solana/web3.js";
import { ArbBot, SwapToken } from './bot';
import dotenv from "dotenv";
import Wallet from './models/userWallet';
import connectDB from '#config/db';
import router from './routes';
import Transaction from '#models/transactionHistory';

const cors = require('cors');
const readline = require('node:readline');

dotenv.config({
    path: ".env",
});

const defaultConfig = {
    solanaEndpoint: clusterApiUrl("mainnet-beta"),
    jupiter: "https://quote-api.jup.ag/v6",
};

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});

const app = express();
const port = 5000;

let mongo = process.env.MONGODB_URI;

// Middleware to parse JSON bodies
app.use(express.json());
connectDB(mongo);
app.use(cors({ origin: true }))
app.use("/api/", router)


// Define the route to add wallet keys
app.post('/add-wallet', async (req: any, res: any): Promise<any> => {

    const { id, walletKey } = req.body;

    if (!id || !walletKey) {
        return res.status(400).json({ error: 'userId and walletKey are required' });
    }

    try {
        // Check if the wallet already exists
        const existingWallet = await Wallet.findById({ id });
        if (!existingWallet) {
            return res.status(404).json({ error: 'User not found' });
        }
        // Check if the wallet is already connected
        if (existingWallet.isWalletConnect) {
            return res.status(400).json({ error: 'Wallet already exists for this user' });
        }
        // Create a new wallet document
        existingWallet.walletKey = walletKey;
        // Save the wallet to the database
        existingWallet.isWalletConnect = true;
        await existingWallet.save();

        res.status(201).json({ message: 'Wallet added successfully', existingWallet });
    } catch (err) {
        console.error('Error adding wallet:', err);
        res.status(500).json({ error: 'Internal server error' });
    }
});


app.post('/start', async (req: any, res: any): Promise<any> => {
    const { id, tokenId, tokenPair, amount, solAmount } = req.body;

    try {
        // Ensure all necessary fields are provided
        if (!id || !tokenId || !tokenPair || !amount || !solAmount) {
            return res.status(400).json({ error: 'id, tokenId, tokenPair, amount, and solAmount are required' });
        }

        // Fetch the wallet using the user id (email)
        const existingWallet = await Wallet.findById({ id });
        if (!existingWallet) {
            return res.status(404).json({ error: 'User not found' });
        }

        // Check if the wallet is already connected
        if (existingWallet.isWalletConnect) {
            return res.status(400).json({ error: 'Wallet already exists for this user' });
        }

        // Decode the secret key from the wallet's walletKey
        let decodedSecretKey;
        try {
            decodedSecretKey = Uint8Array.from(JSON.parse(existingWallet.walletKey));
        } catch (err) {
            return res.status(500).json({ error: 'Failed to decode wallet key' });
        }

        // Determine the initial token amount based on the selected trade pair
        let initialInputToken: SwapToken;
        let initialInputAmount: number;

        switch (tokenPair) {
            case 1:
                initialInputToken = SwapToken.USDC;
                initialInputAmount = amount * 1000000;  // USDC has 6 decimal places
                break;
            case 2:
                initialInputToken = SwapToken.GME;
                initialInputAmount = amount * 1000000000;  // GME has 9 decimal places
                break;
            case 3:
                initialInputToken = SwapToken.DJCAT;
                initialInputAmount = amount * 1000000;  // DJCAT has 6 decimal places
                break;
            case 4:
                initialInputToken = SwapToken.POPCAT;
                initialInputAmount = amount * 1000000000;  // POPCAT has 9 decimal places
                break;
            case 5:
                initialInputToken = SwapToken.NOHAT;
                initialInputAmount = amount * 1000000;  // NOHAT has 6 decimal places
                break;
            default:
                return res.status(400).json({ error: 'Invalid token pair' });
        }

        // Start the bot with the given parameters
        const bot = new ArbBot({
            solanaEndpoint: process.env.SOLANA_ENDPOINT ?? defaultConfig.solanaEndpoint,
            metisEndpoint: process.env.METIS_ENDPOINT ?? defaultConfig.jupiter,
            secretKey: decodedSecretKey,
            firstTradePrice: solAmount * LAMPORTS_PER_SOL,
            targetGainPercentage: 0.1,  // Target gain for the bot
            initialInputToken: initialInputToken,
            initialInputAmount: initialInputAmount,
            currentPair: tokenPair,
        });

        console.log(`Starting bot with:\nToken Pair: ${tokenPair}\nInitial Amount (USDC): ${amount}\nInitial Amount (SOL): ${solAmount == 0 ? "Current Market Price" : solAmount}`);

        // Initialize the bot
        await bot.init();

        // Send response back
        res.status(200).json({
            message: 'Bot initialized successfully',
            botDetails: {
                tokenPair,
                initialAmount: {
                    usdc: amount,
                    sol: solAmount == 0 ? 'Current Market Price' : solAmount
                }
            }
        });

    } catch (error) {
        console.error(error);
        res.status(500).json({ error: 'Internal server error' });
    }
});

// app.post('/start', async (req, res) => {
//     try {
// const { id, amount, solAmount, tradePair } = req.body;

// // Check if the wallet already exists
// const existingWallet = await Wallet.findById({ id });
// if (!existingWallet) {
//     return res.status(404).json({ error: 'User not found' });
// }

// // Check if the wallet is already connected
// if (existingWallet.isWalletConnect) {
//     return res.status(400).json({ error: 'Wallet already exists for this user' });
// }

//       let decodedSecretKey = Uint8Array.from(JSON.parse(existingWallet.walletKey));
//         // console.log("Error after decode", decodedSecretKey);
//         rl.question(`\n***Select Token Pair to trade:**\nPress 1 for USDC/SOL <-> SOL/USDC\nPress 2 for USDC/GME <-> GME/USDC \nPress 3 for USDC/DJCAT <-> DJCAT/USDC\nPress 4 for USDC/POPCAT <-> POPCAT/USDC\nPress 5 for USDC/NOHAT <-> NOHAT/USDC\nEnter your Choice: `, async (tradePair: any) => {
//             console.log("\n");
//             // console.log(typeof(Number(tradePair)));
//             rl.question(`Please enter initial ${tradePair == 1 ? "USDC" : tradePair == 2 ? "GME" : tradePair == 3 ? "DJCAT" : tradePair == 4 ? "POPCAT" : tradePair == 5 ? "NOHAT" : "token"} Amount to start the bot: `, async (amount: any) => {
//                 rl.question(`Please enter expected initial SOL amount to start the bot (Write 0 to buy SOL on current market price): `, async (solAmount: any) => {
//                     const bot = new ArbBot({
//                         solanaEndpoint: process.env.SOLANA_ENDPOINT ?? defaultConfig.solanaEndpoint,
//                         metisEndpoint: process.env.METIS_ENDPOINT ?? defaultConfig.jupiter,
//                         secretKey: decodedSecretKey,
//                         firstTradePrice: solAmount * LAMPORTS_PER_SOL,
//                         targetGainPercentage: 0.1,
//                         initialInputToken: tradePair == 1 ? SwapToken.USDC : tradePair == 2 ? SwapToken.GME : tradePair == 3 ? SwapToken.DJCAT : tradePair == 4 ? SwapToken.POPCAT : tradePair == 5 ? SwapToken.NOHAT : SwapToken.USDC,
//                         // initialInputAmount: 10_000_000,
//                         initialInputAmount: tradePair == 1 || tradePair == 3 || tradePair == 5 ? amount * 1000000 : tradePair == 2 || tradePair == 4 ? amount * 1000000000 : 0,
//                         currentPair: Number(tradePair)
//                     });
//                     console.log(`Initial Amount (USDC): ${amount}`);
//                     console.log(`Initial Amount (SOL): ${solAmount == 0 ? "Current Market Price" : solAmount}`);
//                     await bot.init();
//                     rl.close();
//                 });
//             });
//         });
//     } catch (error) {
//         console.log(error)
//     }
// });


app.get('/', (req, res) => {
    // Send a response to the client
    res.send('Hello, TypeScript + Node.js + Express!');
});


app.get('/getTransactions', async (req: any, res: any): Promise<any> => {
    const existingRecord = await Transaction.find({});
    if (!existingRecord) {
        return res.status(404).json({ error: 'Records not found' });
    }
    res.status(200).json({ status: true, existingRecord });
});


app.listen(port, () => {
    // Log a message when the server is successfully running
    console.log(`Server is running on http://localhost:${port}`);
});