import path from 'node:path';

import { config, eventStream, pgClients } from "@opengis/fastify-table/utils.js";

import mapnik from "../../plugins/mapnik/funcs/mapnik.js";

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

export default async function checkXML(req, reply) {
    const { pg = pgClients.client } = req;
    const send = process.env.NODE_ENV === 'test' || process.env.VITEST
        ? console.log
        : eventStream(reply);

    const errors = { raster: 0, css: 0, service: 0 };
    try {
        const rasters = pg?.pk?.['gis.rasters'] ? await pg.query('select * from gis.rasters').then(el => el.rows || []) : [];

        const css = pg?.pk?.['gis.cartocss'] ? await pg.query('select * from gis.cartocss').then(el => el.rows || []) : [];

        const dataset = pg?.pk?.['gis.dataset'] && false ? await pg.query('select * from gis.dataset').then(el => el.rows || []) : [];

        const total = rasters.length + css.length + dataset.length;
        let successCount = 0;

        send(`Всього растрів: ${rasters.length || '0'}`);

        await rasters.reduce(
            (promise, row, idx) => promise.then(async () => {
                const uploadStatus = path.extname(row.source_path) ? await GetRasterStatus({ path: row.source_path }) : {};

                if (uploadStatus.exists === false) {
                    errors.raster += 1;
                    send(`${idx}/${rasters.length} ERROR: GetRasterStatus: not uploaded (raster:${row.raster_id}/${row.name})`);
                    return null;
                }

                if (uploadStatus.finished === false) {
                    errors.raster += 1;
                    send(`${idx}/${rasters.length} ERROR: GetRasterStatus: upload not finished (raster:${row.raster_id}/${row.name})`);
                    return null;
                }

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

                if (rasterInfo.err) {
                    errors.raster += 1;
                    send(`${idx}/${rasters.length} ERROR: GetRasterInfo: ${rasterInfo.err} (raster:${row.raster_id}/${row.name})`);
                    return null;
                }

                const data = await RenderTile({
                    path: row.source_path,
                    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) {
                    errors.raster += 1;
                    send(`${idx}/${rasters.length} ERROR: RenderTile: ${data.err} (raster:${row.raster_id}/${row.name})`);
                    return null;
                }

                send(`${idx}/${rasters.length} OK: (raster:${row.raster_id}/${row.name})`);
                successCount += 1;
            }),
            Promise.resolve(),
        );

        send(`Всього CSS: ${css.length || '0'}`);

        await css.reduce(
            (promise, row, idx) => promise.then(async () => {
                const data = await RenderTile({
                    path: row.source_path,
                    name: row.source_path ? undefined : row.cartocss_id,
                    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) {
                    errors.css += 1;
                    send(`${idx}/${css.length} ERROR: RenderTile: ${data.err} (css:${row.cartocss_id}/${row.name})`);
                    return null;
                }

                send(`${idx}/${css.length} OK: (css:${row.cartocss_id}/${row.name})`);
                successCount += 1;
            }),
            Promise.resolve(),
        );

        send(`Всього наборів: ${dataset.length || '0'}`);
        // ? place dataset check logic here

        const errorCount = Object.keys(errors).reduce((acc, curr) => acc + errors[curr], 0);
        send(`Всього помилок: ${errorCount || '0'}`);
        send(`Помилки растрів: ${errors.raster || '0'}`);
        send(`Помилки CSS: ${errors.css || '0'}`);
        send(`Помилки наборів: ${errors.dataset || '0'}`);

        send(`Успіх: ${successCount || '0'}/${total || '0'}`);
    }
    catch (err) {
        send(config.local ? err.toString() : 'check error');
        throw err; // allow logger to catch error automatically
    }
    finally {
        send('finish', true);
    }
}
