import path from 'node:path';

import { eventStream } from '@opengis/fastify-table/utils.js';

import mapnik from "./mapnik.js";

const {
    GetRasterStatus, CreateXML, RenderTile, GetRasterInfo,
} = mapnik();

function sequence(arr, fn) {
    const obj = {};
    return arr.reduce(
        (promise, relpath, idx) => promise.then(() => fn({
            relpath, idx,
        })).then(r => Object.assign(obj, r)),
        Promise.resolve(),
    ).then(() => obj);
}

const unsafe = true;

export default async function checkRasterFile({ arr, reply, nocache }) {
    const callback = reply ? eventStream(reply) : () => { };

    let
        createdCount = 0,
        existsCount = 0,
        fileNotFoundCount = 0,
        xmlErrorCount = 0,
        renderErrorCount = 0,
        rasterInfoErrorCount = 0;

    const result = await sequence((arr || []), async ({
        relpath, idx,
    }) => {
        callback(`${idx + 1}/${arr.length} (${relpath})`);

        // check raster upload status, skip for directories
        const uploadStatus = !path.extname(relpath) ? {} : await GetRasterStatus({ path: relpath });

        if (uploadStatus.exists === false) {
            fileNotFoundCount += 1;
            callback(`file not found: ${relpath} `);
            return null;
        }

        // create at xml/:id with name only, always - by path
        const resp = await CreateXML({ path: relpath, nocache }, (msg) => {
            if (typeof msg === 'string' && msg === 'XML creation complete') {
                createdCount += 1;
            }
            if (typeof msg === 'string' && msg.startsWith('XML already exists')) {
                existsCount += 1;
            }
            callback(msg);
        }, unsafe).catch(err => ({ error: err }));

        if (resp.error?.message && resp.error.message.startsWith('5 NOT_FOUND')) {
            fileNotFoundCount += 1;
            callback(`directory not found: ${relpath} `);
            return null;
        }

        if (resp.error) {
            xmlErrorCount += 1;
            callback(`create xml error: ${resp.error.toString()} (${relpath})`);
            return null;
        }

        const data = await RenderTile({
            path: relpath,
            width: 256,
            bbox: [3713463.7081504324, 6088362.176970857, 3713616.5822070027, 6088515.051027427], // /:id/18/155363/91245.png
            ttl: '0',
        }).catch(err => ({ err: err.toString() }));

        if (data.err) {
            renderErrorCount += 1;
            callback(`render error: ${data.err} (${relpath})`);
            return null;
        }
        callback(`render ok: ${relpath} `);

        const { data: rasterInfo, err } = await GetRasterInfo({
            path: relpath,
            ttl: '0',
        }).catch(e => ({ err: e }));

        if (err) {
            rasterInfoErrorCount += 1;
            callback(`raster info error: ${err} (${relpath})`);
            return null;
        }

        return { [relpath]: rasterInfo };
    });

    callback(`${existsCount} - xml exists`);
    callback(`${createdCount} - xml created`);
    callback(`${fileNotFoundCount} - file not found`);
    callback(`${xmlErrorCount} - xml errors`);
    callback(`${renderErrorCount} - render errors`);
    callback(`${rasterInfoErrorCount} - raster info errors`);

    callback('finish', 1);
    return result;
}
