import fs from "fs";
import randomstring from "randomstring";

const TEMP_DIR = "./temp-tts";

const sub_name = randomstring.generate({ length: 5, charset: 'alphanumeric' });

const HOST = "https://office4-chatterbox.wibudev.com";

async function fetchRetry(url: string, options: any = {}, retries = 3) {
    for (let i = 0; i < retries; i++) {
        try {
            return await fetch(url, options);
        } catch (err) {
            console.warn(`Fetch attempt ${i + 1} failed:`, err);
            if (i === retries - 1) throw err;
            await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
        }
    }
}


async function fetchResult(jobId: string, partIndex: number) {
    const res = await fetchRetry(`${HOST}/result/${jobId}`);

    if (!res) {
        throw new Error("Failed to fetch result");
    }

    const type = res.headers.get("content-type") || "";

    if (type.includes("application/json")) {
        try {
            return await res.json();
        } catch {
            throw new Error("Invalid JSON response on fetchResult");
        }
    }

    // Audio response
    const buf = Buffer.from(await res.arrayBuffer());

    if (buf.length < 44) {
        throw new Error("Invalid WAV: too small");
    }

    const file = `${TEMP_DIR}/${jobId}_${sub_name}_${(partIndex + 1).toString().padStart(4, "0")}.wav`;
    fs.writeFileSync(file, buf);
    return { status: "done", filePath: file };
}

export async function main() {
    const jobsPath = TEMP_DIR + "/jobs.json";
    if (!fs.existsSync(jobsPath)) {
        console.error("❌ jobs.json not found");
        process.exit(1);
    }

    // POLLING SEMUA
    const jobs = JSON.parse(fs.readFileSync(jobsPath, "utf-8"));
    console.log("⏳ Waiting for processing...");
    const resultFiles: string[] = [];

    for (let i = 0; i < jobs.length; i++) {
        const jobId = jobs[i];
        let status = "processing";
        let delay = 5000;
        let attempts = 0;

        while (status === "processing" || status === "pending") {
            try {
                const res = await fetchResult(jobId as string, i);
                status = res.status;

                if (status === "done" && res.filePath) {
                    resultFiles.push(res.filePath as string);
                    console.log(`   ✓ Job ${i + 1}/${jobs.length} completed: ${jobId}`);

                    const resFile = await fetchRetry(`${HOST}/file/${jobId}`);
                    if (!resFile) {
                        throw new Error("Failed to fetch file");
                    }
                    const buf = Buffer.from(await res.arrayBuffer());

                    if (buf.length < 44) {
                        throw new Error("Invalid WAV: too small");
                    }

                    const file = `${TEMP_DIR}/${jobId}_${sub_name}_${(i + 1).toString().padStart(4, "0")}.wav`;
                    fs.writeFileSync(file, buf);

                    break;
                } else if (status === "error") {
                    console.error(
                        `   ❌ Job ${i + 1}/${jobs.length} failed: ${res.error || "Unknown error"}`
                    );
                    throw new Error(`Job ${jobId} failed`);
                }
            } catch (error) {
                console.error(`❌ Error fetching result for job ${i + 1}:`, error);
                process.exit(1);
            }

            attempts++;
            await new Promise((r) => setTimeout(r, delay));
            delay = Math.min(delay * 1.2, 5000);

            // Timeout after 2 minutes
            if (attempts > 80) {
                console.error(`❌ Job ${jobId} timeout after 2 minutes`);
                process.exit(1);
            }
        }
    }

    console.log("🎉 DONE!");
    return resultFiles;
}

if (import.meta.main) {
    main().then((resultFiles) => {
        console.log("Result files:", resultFiles);
    });
}