/**
 * Mint NFT to Token Bound Account (TBA) Script
 * 
 * This script mints an NFT directly to a Token Bound Account (ERC-6551 account)
 * for token ID 1 with a specified salt
 * 
 * Usage:
 * 1. Create a .env file and set the following environment variables:
 *    - PRIVATE_KEY: Private key of the NFT holder 
 * 
 * 2. Run the script:
 *    npm run mint-to-tba
 *    or
 *    yarn mint-to-tba
 */

import { GoTakeSDK, NetworkId } from "../src";
import { getContractAddress } from 'gotake-contracts';
import * as dotenv from 'dotenv';
import { ethers } from 'ethers';

dotenv.config();

// NFT metadata configuration - Customize your NFT here
const nftMetadata = {
    title: "My TBA NFT",              // NFT title
    description: "NFT minted to TBA", // NFT description
    thumbnailUrl: "",                 // Thumbnail URL (optional)
    creator: "",                      // Will be set to signer's address
    totalSeasons: 1,                  // Total seasons
    totalEpisodes: 1,                 // Total episodes
    genres: ["Action", "Drama"],      // Genre tags
    posterUri: ""                     // Poster URI
};

// TBA configuration
const tbaConfig = {
    tokenId: 1,                       // Target token ID is 1
    salt: "0x0000000000000000000000000000000000000000000000000000000000000001" // Custom salt
};

async function main() {
    // Check required environment variables
    if (!process.env.PRIVATE_KEY) {
        throw new Error("PRIVATE_KEY is not defined in environment variables. Please set it in your .env file");
    }

    try {
        // Get network ID - using Base Sepolia testnet
        const networkId = NetworkId.BASE_SEPOLIA;
        console.log(`Using network: Base Sepolia (ID: ${networkId})`);

        // Create Provider and Signer
        const rpcUrl = "https://sepolia.base.org";
        const ethersProvider = new ethers.providers.JsonRpcProvider(rpcUrl);
        const ethersSigner = new ethers.Wallet(process.env.PRIVATE_KEY, ethersProvider);
        const signerAddress = await ethersSigner.getAddress();
        console.log(`Using address: ${signerAddress}`);

        // Set creator to signer's address
        nftMetadata.creator = signerAddress;

        // Initialize SDK
        const sdk = new GoTakeSDK({
            network: networkId,
            provider: ethersProvider,
            signer: ethersSigner,
        });
        console.log("SDK initialized successfully");

        // Get contract addresses from config
        const tokenContract = getContractAddress('base_sepolia', 'ipnft');
        const implementation = getContractAddress('base_sepolia', 'accountImplementation');

        console.log(`NFT contract address: ${tokenContract}`);
        console.log(`Account implementation address: ${implementation}`);
        console.log(`Target Token ID for TBA: ${tbaConfig.tokenId}`);
        console.log(`Using salt: ${tbaConfig.salt}`);

        // Get current gas price recommendations
        console.log("Getting current gas price recommendations...");
        const gasPrices = await sdk.getGasPrice({
            multiplier: 1.2,
            priorityMultiplier: 1.5
        });

        console.log("Current gas prices:");
        if (gasPrices.baseFeePerGas) {
            console.log(`Base fee: ${ethers.utils.formatUnits(gasPrices.baseFeePerGas, "gwei")} gwei`);
        }
        console.log(`Max fee per gas: ${ethers.utils.formatUnits(gasPrices.maxFeePerGas, "gwei")} gwei`);
        if (gasPrices.maxPriorityFeePerGas) {
            console.log(`Max priority fee: ${ethers.utils.formatUnits(gasPrices.maxPriorityFeePerGas, "gwei")} gwei`);
        }

        // Transaction options including gas configuration
        const transactionOptions = {
            gasConfig: {
                gasLimit: 500000, // Manual gas limit to prevent estimation issues
                maxFeePerGas: gasPrices.maxFeePerGas, // Use recommended values
                maxPriorityFeePerGas: gasPrices.maxPriorityFeePerGas // Use recommended values
            }
        };
        console.log("Using transaction options with recommended gas values");
        console.log(`Gas Limit: ${transactionOptions.gasConfig.gasLimit}`);

        // Calculate TBA address
        console.log("Calculating TBA address...");
        const tbaAddress = await sdk.account.computeTBAAddress({
            tokenContract,
            tokenId: tbaConfig.tokenId,
            salt: tbaConfig.salt
        });
        console.log(`Calculated TBA address: ${tbaAddress}`);

        // Check if TBA exists
        const code = await ethersProvider.getCode(tbaAddress);
        const tbaExists = code !== '0x';

        // If TBA doesn't exist, create it
        if (!tbaExists) {
            console.log("TBA does not exist, creating...");
            const businessParams = {
                tokenContract: tokenContract,
                tokenId: tbaConfig.tokenId,
                salt: tbaConfig.salt
            };

            const createResult = await sdk.account.createTBA(businessParams, transactionOptions);

            console.log(`TBA creation successful: ${createResult.tbaAddress}`);
            console.log(`Transaction hash: ${createResult.tx.hash}`);
            console.log("Waiting for transaction confirmation...");
            await ethersProvider.waitForTransaction(createResult.tx.hash);
            console.log("TBA creation confirmed");
        } else {
            console.log(`TBA already exists: ${tbaAddress}`);
        }

        // Mint NFT to TBA address
        console.log(`Minting NFT to TBA address: ${tbaAddress}...`);
        const mintResult = await sdk.ipnft.mint(
            tbaAddress,
            nftMetadata,
            transactionOptions
        );

        console.log(`NFT mint transaction submitted, hash: ${mintResult.tx.hash}`);

        // Wait for transaction confirmation
        console.log("Waiting for transaction confirmation...");
        await ethersProvider.waitForTransaction(mintResult.tx.hash);
        console.log(`NFT mint successful! Token ID: ${mintResult.tokenId.toString()}`);

        // Get NFT details
        console.log("Fetching NFT details...");
        const nftDetails = await sdk.ipnft.getNFTDetails(mintResult.tokenId);

        console.log("NFT Details:");
        console.log(`Token ID: ${nftDetails.tokenId.toString()}`);
        console.log(`Owner: ${nftDetails.owner}`);
        console.log(`Series Title: ${nftDetails.seriesTitle}`);
        console.log(`Description: ${nftDetails.description}`);
        console.log(`URI: ${nftDetails.uri}`);
        console.log(`Total Seasons: ${nftDetails.totalSeasons.toString()}`);
        console.log(`Total Episodes: ${nftDetails.totalEpisodes.toString()}`);
        console.log(`Genres: ${nftDetails.genres.join(', ')}`);
        console.log(`Creators: ${nftDetails.creators.join(', ')}`);
        console.log(`Poster URI: ${nftDetails.posterUri}`);
        console.log(`Created At: ${new Date(nftDetails.createdAt.toNumber() * 1000).toISOString()}`);

        console.log("Operation completed successfully!");
    } catch (error) {
        console.error("Error minting NFT to TBA:");
        console.error(error);
        process.exitCode = 1;
    }
}

main().catch(error => {
    console.error("Error executing script:");
    console.error(error);
    process.exitCode = 1;
}); 