/**
 * Video Upload and NFT Minting Script
 * 
 * This script demonstrates the complete video upload flow including:
 * 1. Checking and creating a TBA (Token Bound Account)
 * 2. Uploading a video to the platform
 * 3. Monitoring video processing status
 * 4. Minting an IP NFT
 * 
 * Usage:
 * 1. Create a .env file and set the following environment variables:
 *    - PRIVATE_KEY: Private key of the NFT holder
 *    - API_KEY: GoodTake API key (optional)
 * 
 * 2. Prepare a test video file and place it in scripts/assets/ directory
 * 
 * 3. Run the script:
 *    npm run upload-video
 *    or
 *    yarn upload-video
 */

import { GoTakeSDK, NetworkId, VideoStatus } from "../src";
import * as dotenv from 'dotenv';
import { ethers } from 'ethers';
import * as fs from 'fs';
import * as path from 'path';
import { Blob } from 'fetch-blob';
import File from 'fetch-blob/file';

dotenv.config();

// Utility function: Convert file system file to browser File object
function createFileFromPath(filePath: string): File {
    const fileName = path.basename(filePath);
    const fileBuffer = fs.readFileSync(filePath);
    const fileBlob = new Blob([fileBuffer]);
    return new File([fileBlob], fileName, { type: getMimeType(fileName) });
}

// Utility function: Get MIME type based on file extension
function getMimeType(fileName: string): string {
    const ext = fileName.split('.').pop()?.toLowerCase();
    const mimeTypes: Record<string, string> = {
        'mp4': 'video/mp4',
        'mov': 'video/quicktime',
        'avi': 'video/x-msvideo',
        'webm': 'video/webm'
    };
    return mimeTypes[ext || ''] || 'application/octet-stream';
}

// Utility function: Wait for specified time
function sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
}

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");
    }

    const videoFilePath = path.join(__dirname, 'assets', 'sample-video.mp4');
    if (!fs.existsSync(videoFilePath)) {
        throw new Error(`Test video file not found: ${videoFilePath}`);
    }

    try {
        console.log("=== GoodTake Video Upload Demo ===");

        // 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 userAddress = await ethersSigner.getAddress();

        console.log(`Using address: ${userAddress}`);

        // Initialize SDK
        const sdk = new GoTakeSDK({
            network: NetworkId.BASE_SEPOLIA,
            provider: ethersProvider,
            signer: ethersSigner,
            apiEndpoint: process.env.API_ENDPOINT || 'https://api.goodtake.io',
            apiKey: process.env.API_KEY
        });
        console.log("SDK initialized successfully");

        // Step 1: Check and create TBA if needed
        console.log("\n=== Step 1: Check/Create TBA ===");
        const { tbaAddress, isNew } = await sdk.checkAndCreateTBA();
        if (isNew) {
            console.log(`Created new TBA: ${tbaAddress}`);
        } else {
            console.log(`Using existing TBA: ${tbaAddress}`);
        }

        // Step 2: Prepare video file and upload
        console.log("\n=== Step 2: Upload Video ===");
        const videoFile = createFileFromPath(videoFilePath);
        console.log(`Preparing to upload: ${videoFile.name} (${videoFile.size} bytes)`);

        const videoMetadata = {
            title: "GoodTake Test Video",
            description: "This is a test video uploaded via SDK",
            tags: ["test", "sdk", "demo"],
            creator: userAddress
        };

        console.log("Uploading video...");
        const videoId = await sdk.uploadVideo(videoFile, videoMetadata);
        console.log(`Video uploaded successfully! Video ID: ${videoId}`);

        // Step 3: Monitor video processing status
        console.log("\n=== Step 3: Monitor Video Processing ===");
        console.log("Setting up status monitoring...");

        // Method A: Using polling
        console.log("Using polling to monitor processing:");

        let videoReady = false;
        while (!videoReady) {
            const status = await sdk.getVideoStatus(videoId);
            console.log(`Current status: ${status.status}, Progress: ${status.progress || 'unknown'}%`);

            if (status.status === VideoStatus.READY || status.status === VideoStatus.MINT_READY) {
                videoReady = true;
                console.log("Video processing completed, ready for minting");
            } else if (status.status === VideoStatus.ERROR) {
                throw new Error(`Video processing failed: ${status.error?.message || 'Unknown error'}`);
            } else {
                console.log("Waiting for processing to complete...");
                await sleep(5000);
            }
        }

        // Step 4: Mint IP NFT
        console.log("\n=== Step 4: Mint IP NFT ===");
        console.log("Starting NFT minting...");

        const mintResult = await sdk.mintIPNFT(videoId);
        console.log("NFT minted successfully!");
        console.log(`Token ID: ${mintResult.tokenId}`);
        console.log(`Transaction Hash: ${mintResult.transactionHash}`);
        console.log(`Owner: ${mintResult.owner}`);
        console.log(`Metadata: ${JSON.stringify(mintResult.metadata, null, 2)}`);

        // Display final status
        const finalStatus = await sdk.getVideoStatus(videoId);
        console.log("\n=== Final Status ===");
        console.log(`Video ID: ${videoId}`);
        console.log(`Status: ${finalStatus.status}`);
        if (finalStatus.assetInfo?.playbackUrl) {
            console.log(`Playback URL: ${finalStatus.assetInfo.playbackUrl}`);
        }
        if (finalStatus.mintInfo) {
            console.log(`NFT Token ID: ${finalStatus.mintInfo.tokenId}`);
            console.log(`NFT Transaction: ${finalStatus.mintInfo.transactionHash}`);
        }

        console.log("\nProcess completed! Video uploaded and minted as NFT successfully.");

    } catch (error) {
        console.error("Error during video upload process:");
        console.error(error);
        process.exitCode = 1;
    }
}

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