import * as fs from 'fs';
import * as path from 'path';
import { convertImageVton, convertImage } from '../lib/image-converter';
import * as dotenv from 'dotenv';
import sharp from 'sharp';

dotenv.config();

const clothesDir = 'D:\\projects\\random_video_maker\\input';
const outputDir = 'generated';

const comfyBaseUrl = process.env.SERVER1_COMFY_BASE_URL;
const comfyOutputDir = process.env.SERVER1_COMFY_OUTPUT_DIR;

function getNextIndex(directory: string): number {
    if (!fs.existsSync(directory)) {
        fs.mkdirSync(directory, { recursive: true });
        return 0;
    }
    const dirs = fs.readdirSync(directory, { withFileTypes: true })
        .filter(dirent => dirent.isDirectory())
        .map(dirent => dirent.name);

    const vtonDirs = dirs.filter(dir => dir.startsWith('vton_'));
    if (vtonDirs.length === 0) {
        return 0;
    }
    const indices = vtonDirs.map(dir => {
        const match = dir.match(/vton_(\d+)/);
        return match ? parseInt(match[1], 10) : -1;
    });
    return Math.max(...indices) + 1;
}

function getRandomFile(directory: string): string {
    const files = fs.readdirSync(directory).filter(file => /\.(jpg|png|jpeg)$/i.test(file));
    if (files.length === 0) {
        throw new Error(`No image files found in directory: ${directory}`);
    }
    const randomFile = files[Math.floor(Math.random() * files.length)];
    return path.join(directory, randomFile);
}

async function generateVtonImages() {
    if (!comfyBaseUrl || !comfyOutputDir) {
        throw new Error("ComfyUI URL or Output Directory is not set in environment variables.");
    }

    let index = getNextIndex(outputDir);

    const comfyInputDir = comfyOutputDir.replace("output", "input");

    while (true) { // Infinite loop
        const iterationDir = path.join(outputDir, `vton_${index}`);
        fs.mkdirSync(iterationDir, { recursive: true });

        try {
            const personOrigPath = getRandomFile(clothesDir);
            const clothOrigPath = getRandomFile(clothesDir);

            fs.copyFileSync(personOrigPath, path.join(iterationDir, '1-personOrig.png'));
            fs.copyFileSync(clothOrigPath, path.join(iterationDir, '3-clothOrig.png'));

            const personOrigFileName = path.basename(personOrigPath);
            const clothOrigFileName = path.basename(clothOrigPath);

            fs.copyFileSync(personOrigPath, path.join(comfyInputDir, personOrigFileName));
            fs.copyFileSync(clothOrigPath, path.join(comfyInputDir, clothOrigFileName));

            console.log(`Processing person: ${personOrigPath}, cloth: ${clothOrigPath}`);

            const cleanePersonImagePath = await convertImage("请把姿势改成站立的，转换成全身照片。去掉衣服，只保留白色运动文胸和白色短裤。双脚保持赤脚。背景为浅灰色。", personOrigFileName, comfyBaseUrl, comfyOutputDir, { width: 720, height: 1280 });
            fs.copyFileSync(cleanePersonImagePath, path.join(iterationDir, '2-personCleaned.png'));
            const cleanedPersonFileName = path.basename(cleanePersonImagePath);
            fs.copyFileSync(cleanePersonImagePath, path.join(comfyInputDir, cleanedPersonFileName));

            const cleanedClothImagePath = await convertImage("请将图1中的上衣、下装和配饰分别提取出来，放到同一个浅灰色的背景上。", clothOrigFileName, comfyBaseUrl, comfyOutputDir, { width: 720, height: 1280 });
            fs.copyFileSync(cleanedClothImagePath, path.join(iterationDir, '4-clothCleaned.png'));
            const cleanedClothFileName = path.basename(cleanedClothImagePath);
            fs.copyFileSync(cleanedClothImagePath, path.join(comfyInputDir, cleanedClothFileName));

            const outputFilename = `vton_final_${index}.png`;
            const generatedImagePath = await convertImageVton(cleanedPersonFileName, cleanedClothFileName, outputFilename, comfyBaseUrl, comfyOutputDir, { width: 720, height: 1280 });

            if (generatedImagePath) {
                fs.copyFileSync(generatedImagePath, path.join(iterationDir, '5-finalResult.png'));
                console.log(`Generated image saved to ${generatedImagePath}`);

                // --- Create composite image ---
                const imagePaths = [
                    path.join(iterationDir, '1-personOrig.png'),
                    path.join(iterationDir, '3-clothOrig.png'),
                    path.join(iterationDir, '2-personCleaned.png'),
                    path.join(iterationDir, '4-clothCleaned.png'),
                    path.join(iterationDir, '5-finalResult.png')
                ];

                const resizedImages = [];
                let totalWidth = 10; // Initial left margin
                const resizedHeight = 720;

                for (const imagePath of imagePaths) {
                    const image = sharp(imagePath);
                    const metadata = await image.metadata();
                    if (!metadata.width || !metadata.height) {
                        throw new Error(`Could not get metadata for image ${imagePath}`);
                    }
                    const resizedWidth = Math.round((metadata.width / metadata.height) * resizedHeight);

                    const resizedImageBuffer = await image.resize(resizedWidth, resizedHeight).toBuffer();
                    resizedImages.push({
                        buffer: resizedImageBuffer,
                        width: resizedWidth
                    });
                    totalWidth += resizedWidth + 10; // Add image width and right margin
                }

                const compositeOps = [];
                let currentLeft = 10; // Start with left margin

                for (const img of resizedImages) {
                    compositeOps.push({
                        input: img.buffer,
                        top: 10, // 10px top margin
                        left: currentLeft
                    });
                    currentLeft += img.width + 10; // Move to the next position
                }

                await sharp({
                    create: {
                        width: totalWidth,
                        height: 740,
                        channels: 4,
                        background: { r: 255, g: 255, b: 255, alpha: 1 }
                    }
                })
                    .composite(compositeOps)
                    .toFile(path.join(iterationDir, 'process.png'));

                console.log(`Generated composite image process.png in ${iterationDir}`);
                // --- End of composite image creation ---

                index++;
            } else {
                console.error(`Failed to generate image for index ${index}`);
            }
        } catch (error) {
            console.error("An error occurred during image generation:", error);
            // Optional: wait for a bit before retrying to avoid spamming errors
            await new Promise(resolve => setTimeout(resolve, 5000));
        }
    }
}

generateVtonImages().catch(console.error);
