import * as fs from 'fs/promises';
import * as path from 'path';
import axios from 'axios';
import dotenv from 'dotenv';

dotenv.config();

interface VideoSize {
    width: number;
    height: number;
}

async function generateVideo(
    prompt: string,
    imagePath: string,
    newFileName: string,
    comfyBaseUrl: string,
    comfyOutputDir: string,
    size: VideoSize = { width: 720, height: 1280 }
): Promise<string> {
    const COMFY_BASE_URL = comfyBaseUrl.replace(/\/$/, '');
    const COMFY_OUTPUT_DIR = comfyOutputDir;
    const workflow = JSON.parse(await fs.readFile('src/comfyworkflows/generate_video_text.json', 'utf-8'));
    workflow['27']['inputs']['text'] = prompt;
    workflow['28']['inputs']['width'] = size.width;
    workflow['28']['inputs']['height'] = size.height;

    const response = await axios.post(`${COMFY_BASE_URL}/prompt`, { prompt: workflow });
    const promptId = response.data.prompt_id;

    let history;
    do {
        await new Promise(resolve => setTimeout(resolve, 1000));
        const historyResponse = await axios.get(`${COMFY_BASE_URL}/history/${promptId}`);
        history = historyResponse.data[promptId];
    } while (!history || Object.keys(history.outputs).length === 0);

    const files = await fs.readdir(COMFY_OUTPUT_DIR!);

    // find latest .mp4 file (video) in the comfy output dir
    const generatedFiles = files.filter(file => file.endsWith('.mp4'));

    const fileStats = await Promise.all(
        generatedFiles.map(async (file) => {
            const stat = await fs.stat(path.join(COMFY_OUTPUT_DIR!, file));
            return { file, mtime: stat.mtime };
        })
    );

    if (fileStats.length === 0) {
        throw new Error('No generated mp4 files found in comfy output directory.');
    }

    fileStats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());

    const latestFile = fileStats[0].file;
    const newFilePath = path.resolve('./generated', newFileName);

    await fs.mkdir('./generated', { recursive: true });

    const sourcePath = path.join(COMFY_OUTPUT_DIR!, latestFile);
    await fs.copyFile(sourcePath, newFilePath);

    // Handle the static image (.png)
    // Expected image name: same base name as the video, but .png extension
    const expectedImageName = path.basename(newFileName, path.extname(newFileName)) + '.png';

    const pngFiles = files.filter(file => file.endsWith('.png'));

    let sourcePngFile: string | null = null;

    // Prefer exact match (Comfy sometimes names the image exactly as the video base name)
    if (pngFiles.includes(expectedImageName)) {
        sourcePngFile = expectedImageName;
    } else if (pngFiles.length > 0) {
        // Fallback: pick the most recent .png by timestamp
        const pngStats = await Promise.all(
            pngFiles.map(async (file) => {
                const stat = await fs.stat(path.join(COMFY_OUTPUT_DIR!, file));
                return { file, mtime: stat.mtime };
            })
        );
        pngStats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
        sourcePngFile = pngStats[0].file;
    }

    if (sourcePngFile) {
        const targetPngPath = path.resolve('./generated', expectedImageName);
        // Delete existing target image if present
        try {
            await fs.unlink(targetPngPath);
        } catch (err) {
            // ignore if not exists
        }

        const sourcePngPath = path.join(COMFY_OUTPUT_DIR!, sourcePngFile);
        // Copy and rename the png to the generated folder with the expected name
        await fs.copyFile(sourcePngPath, targetPngPath);
    }

    return newFilePath;
}

export { generateVideo };
