"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const axios_1 = require("axios");
const fs_1 = require("fs");
const path_1 = require("path");
const DRY_RUN = process.argv.includes("--dry-run");
const DEBUG_RESPONSE = process.argv.includes("--debug-response");
const API_KEY = process.env.ROBOFLOW_API_KEY ?? "lfcvBCx9MlyYTlfZamTG";
const WORKFLOW_URL = "https://serverless.roboflow.com/rugkpsi/workflows/general-segmentation-api-8";
const ASSETS_DIR = (0, path_1.join)(process.cwd(), "src", "assets");
const SERVICE_FILE = (0, path_1.join)(process.cwd(), "src", "appapi", "numberplate", "numberplate.service.ts");
const CARS = [
    {
        slug: "mercedes-benz-g",
        label: "Mercedes-Benz G",
        front: { file: "mercedes-benz-g-front.webp", width: 933, height: 700 },
        back: { file: "mercedes-benz-g-back.webp", width: 933, height: 700 },
    },
    {
        slug: "lamborghini-urus",
        label: "Lamborghini Urus",
        front: { file: "lamborghini-urus-front.jpeg", width: 1536, height: 1024 },
        back: { file: "lamborghini-urus-back.jpeg", width: 1280, height: 853 },
    },
    {
        slug: "mercedes-amg-g63",
        label: "Mercedes-AMG G63",
        front: { file: "mercedes-amg-g63-front.jpeg", width: 1536, height: 1024 },
        back: { file: "mercedes-amg-g63-back.jpeg", width: 1280, height: 853 },
    },
    {
        slug: "mercedes-amg-gt-r",
        label: "Mercedes-AMG GT R",
        front: { file: "mercedes-amg-gt-r-front.jpeg", width: 1536, height: 1024 },
        back: { file: "mercedes-amg-gt-r-back.jpeg", width: 1280, height: 853 },
    },
    {
        slug: "porsche-911-gt3-rs",
        label: "Porsche 911 GT3 RS",
        front: { file: "porsche-911-gt3-rs-front.jpeg", width: 1536, height: 1024 },
        back: { file: "porsche-911-gt3-rs-back.jpeg", width: 1280, height: 853 },
    },
    {
        slug: "kawasaki",
        label: "Kawasaki",
        back: { file: "kawasaki-back.jpeg", width: 1280, height: 960 },
    },
    {
        slug: "slingshot-s",
        label: "Slingshot S",
        front: { file: "slingshot-s-front.jpeg", width: 1280, height: 853 },
        back: { file: "slingshot-s-back.jpeg", width: 1280, height: 853 },
    },
];
async function infer(filePath) {
    const buf = await fs_1.promises.readFile(filePath);
    const base64 = buf.toString("base64");
    try {
        const res = await axios_1.default.post(WORKFLOW_URL, {
            api_key: API_KEY,
            inputs: {
                image: { type: "base64", value: base64 },
                classes: "License_Plate",
            },
        }, {
            headers: { "Content-Type": "application/json" },
            timeout: 30_000,
        });
        if (DEBUG_RESPONSE) {
            console.log("  [DEBUG] Raw workflow response:", JSON.stringify(res.data, null, 2));
        }
        return parseWorkflowResponse(res.data);
    }
    catch (err) {
        console.error(`  [ERROR] Roboflow request failed for ${filePath}: ${err.message}`);
        return null;
    }
}
function parseWorkflowResponse(data) {
    const outputs = data?.outputs ?? [];
    for (const output of outputs) {
        const candidates = [
            output?.predictions?.predictions,
            output?.predictions,
            output?.detections?.predictions,
            output?.detections,
        ];
        const predictions = candidates.find((c) => Array.isArray(c));
        const image = output?.predictions?.image ?? output?.image ?? { width: 0, height: 0 };
        if (predictions) {
            return { predictions, image };
        }
    }
    return null;
}
function bestPlateDetection(result) {
    const plates = result.predictions.filter((p) => p.class === "License_Plate");
    if (!plates.length)
        return null;
    return plates.reduce((best, p) => (p.confidence > best.confidence ? p : best));
}
function round(n) {
    return Math.round(n);
}
function buildCarAssetsBlock(results, fallbacks) {
    const lines = [
        `const DEFAULT_CAR_SLUG = "mercedes-benz-g";`,
        ``,
        `const carAssets: Record<string, CarAssetEntry> = {`,
    ];
    for (const car of results) {
        const backDet = car.back.detection ?? fallbacks.get(car.slug)?.get("back");
        const bd = backDet ?? { x: 0, y: 0, width: 100, height: 30, confidence: 0 };
        lines.push(`  "${car.slug}": {`);
        lines.push(`    label: "${car.label}",`);
        if (car.front) {
            const frontDet = car.front.detection ?? fallbacks.get(car.slug)?.get("front");
            const fd = frontDet ?? { x: 0, y: 0, width: 100, height: 30, confidence: 0 };
            lines.push(`    front: {`);
            lines.push(`      path: join(process.cwd(), "src", "assets", "${car.front.file}"),`);
            lines.push(`      width: ${car.front.width},`);
            lines.push(`      height: ${car.front.height},`);
            lines.push(`      detection: { x: ${round(fd.x)}, y: ${round(fd.y)}, width: ${round(fd.width)}, height: ${round(fd.height)}, confidence: ${fd.confidence.toFixed(4)}, class: "License_Plate" },`);
            lines.push(`    },`);
        }
        lines.push(`    back: {`);
        lines.push(`      path: join(process.cwd(), "src", "assets", "${car.back.file}"),`);
        lines.push(`      width: ${car.back.width},`);
        lines.push(`      height: ${car.back.height},`);
        lines.push(`      detection: { x: ${round(bd.x)}, y: ${round(bd.y)}, width: ${round(bd.width)}, height: ${round(bd.height)}, confidence: ${bd.confidence.toFixed(4)}, class: "License_Plate" },`);
        lines.push(`    },`);
        lines.push(`  },`);
    }
    lines.push(`};`);
    return lines.join("\n");
}
const BLOCK_START = `const DEFAULT_CAR_SLUG = "mercedes-benz-g";`;
const BLOCK_END = `};`;
function patchServiceFile(source, newBlock) {
    const startIdx = source.indexOf(BLOCK_START);
    if (startIdx === -1)
        throw new Error(`Could not find anchor "${BLOCK_START}" in service file`);
    const assetsStart = source.indexOf("const carAssets: Record<string, CarAssetEntry> = {", startIdx);
    if (assetsStart === -1)
        throw new Error("Could not find carAssets block");
    let depth = 0;
    let endIdx = -1;
    for (let i = assetsStart; i < source.length; i++) {
        if (source[i] === "{")
            depth++;
        if (source[i] === "}") {
            depth--;
            if (depth === 0) {
                endIdx = source[i + 1] === ";" ? i + 2 : i + 1;
                break;
            }
        }
    }
    if (endIdx === -1)
        throw new Error("Could not find end of carAssets block");
    return source.slice(0, startIdx) + newBlock + source.slice(endIdx);
}
const MANUAL_FALLBACKS = new Map([
    ["mercedes-benz-g", new Map([
            ["front", { x: 466, y: 455, width: 166, height: 42, confidence: 1, class: "License_Plate" }],
            ["back", { x: 478, y: 455, width: 142, height: 38, confidence: 1, class: "License_Plate" }],
        ])],
    ["lamborghini-urus", new Map([
            ["front", { x: 768, y: 645, width: 368, height: 82, confidence: 1, class: "License_Plate" }],
            ["back", { x: 627, y: 435, width: 270, height: 77, confidence: 1, class: "License_Plate" }],
        ])],
    ["mercedes-amg-g63", new Map([
            ["front", { x: 737, y: 625, width: 384, height: 90, confidence: 1, class: "License_Plate" }],
            ["back", { x: 640, y: 554, width: 290, height: 68, confidence: 1, class: "License_Plate" }],
        ])],
    ["mercedes-amg-gt-r", new Map([
            ["front", { x: 768, y: 655, width: 323, height: 82, confidence: 1, class: "License_Plate" }],
            ["back", { x: 640, y: 529, width: 320, height: 68, confidence: 1, class: "License_Plate" }],
        ])],
    ["porsche-911-gt3-rs", new Map([
            ["front", { x: 768, y: 614, width: 350, height: 82, confidence: 1, class: "License_Plate" }],
            ["back", { x: 614, y: 486, width: 256, height: 85, confidence: 1, class: "License_Plate" }],
        ])],
    ["kawasaki", new Map([
            ["back", { x: 640, y: 540, width: 165, height: 36, confidence: 1, class: "License_Plate" }],
        ])],
    ["slingshot-s", new Map([
            ["front", { x: 640, y: 545, width: 200, height: 44, confidence: 1, class: "License_Plate" }],
            ["back", { x: 640, y: 475, width: 185, height: 40, confidence: 1, class: "License_Plate" }],
        ])],
]);
let _;
async function main() {
    console.log(`\n=== Calibrating car plate positions via Roboflow ===`);
    if (DRY_RUN)
        console.log("(dry-run mode — service file will NOT be modified)\n");
    const calibrationResults = [];
    for (const car of CARS) {
        console.log(`\n[${car.label}]`);
        const calibrated = {
            slug: car.slug,
            label: car.label,
            front: car.front ? { file: car.front.file, width: car.front.width, height: car.front.height, detection: null } : undefined,
            back: { file: car.back.file, width: car.back.width, height: car.back.height, detection: null },
        };
        const sides = car.front ? ["front", "back"] : ["back"];
        for (const side of sides) {
            const asset = car[side];
            const filePath = (0, path_1.join)(ASSETS_DIR, asset.file);
            process.stdout.write(`  ${side}: ${asset.file} ... `);
            const result = await infer(filePath);
            if (!result) {
                console.log("FAILED (keeping fallback)");
                continue;
            }
            const det = bestPlateDetection(result);
            if (!det) {
                console.log(`no plate detected (${result.predictions.length} predictions, keeping fallback)`);
                continue;
            }
            console.log(`✓  x=${round(det.x)} y=${round(det.y)} w=${round(det.width)} h=${round(det.height)} conf=${(det.confidence * 100).toFixed(1)}%`);
            calibrated[side].detection = det;
        }
        calibrationResults.push(calibrated);
    }
    const newBlock = buildCarAssetsBlock(calibrationResults, MANUAL_FALLBACKS);
    console.log("\n=== New carAssets block ===\n");
    console.log(newBlock);
    if (!DRY_RUN) {
        const source = await fs_1.promises.readFile(SERVICE_FILE, "utf8");
        const patched = patchServiceFile(source, newBlock);
        await fs_1.promises.writeFile(SERVICE_FILE, patched, "utf8");
        console.log(`\n✓ Patched ${SERVICE_FILE}`);
    }
    else {
        console.log("\n(dry-run: skipped writing service file)");
    }
}
main().catch((err) => {
    console.error(err);
    process.exit(1);
});
//# sourceMappingURL=calibrate-car-plates.js.map