import { getSelectVal, getSelect, getTemplates } from '@opengis/fastify-table/utils.js';

export async function attachClassifiers(rowOrRows, classifiers, table) {
    const rows = Array.isArray(rowOrRows) ? rowOrRows : [rowOrRows];

    const list = getTemplates(['cls', 'select']);

    // classifiers as object
    if (table) {
        await Promise.all(rows.map(async row => {
            await Promise.all(Object.keys(row).filter(key => classifiers?.[key] || list.map(el => el[0]).includes(`${table}.${key}`) || list.map(el => el[0]).includes(key)).map(async key => {
                const clsAsColumn = list.map(el => el[0]).includes(key);
                const arr = await getSelectVal({ name: classifiers?.[key] || (clsAsColumn ? key : `${table}.${key}`), values: [row[key]], ar: true });
                const val = arr?.find?.(el => el.id && el.id.toString() === row[key].toString());
                if (val?.text) { row[`${key}_data`] = val; }
                row[key] = val?.text || val || row[key]; // for frontend
                row[`${key}_text`] = val?.text || val || row[key]; // legacy?
            }));
        }));
        return rowOrRows;
    }

    // classifiers as array of objects
    await Promise.all(rows.map(async row => {
        (classifiers || []).filter(item => item.classifier && item.name && row[item.name]).map(async ({ name, classifier }) => {
            const arr = await getSelectVal({ name: classifier, values: [row[name]], ar: true });
            const val = arr?.find?.(el => el.id === row[name]);
            if (val?.text) { row[`${name}_data`] = val; }
            row[name] = val?.text || val || row[name]; // for frontend
            row[`${name}_text`] = val?.text || val || row[name]; // legacy?
        });
    }));

    /* for (const row of rows) {
        for (const { name, classifier } of classifiers) {
            const value = row[name];
            if (value != null && classifier) {

                const match = await getSelectVal({ name: classifier, values: [value] });
                const matchVal = Object.values(match)?.[0]

                if (typeof matchVal === 'object' && matchVal !== null) {
                    row[`${name}_data`] = matchVal;
                } else if (
                    typeof matchVal === 'string' && matchVal !== null
                ) {
                    row[`${name}_text`] = matchVal;
                };
                
            }
        }
    } */

    return rowOrRows;
}

export async function populateFilterOptions({ pg, table, filters, columns, whereConditions }) {
    if (!filters?.length || !table || !columns?.length) return;

    const optimizedSQL = `select * from ${table} where ${whereConditions || '1=1'}`;

    await Promise.all(
        filters
            .filter(
                (el) =>
                    el.id &&
                    el.type !== "Autocomplete" &&
                    !el.sql &&
                    !el.options?.find?.((item) => item.sql)
            )
            .map(async (el) => {
                const cls = el.data ? await getSelect(el.data, pg) : null;

                if (!cls && !el.type?.includes?.("Check")) return;
                const { dataTypeID } = (columns || []).find((item) => item.name === el.id) || {};

                const q = pg.pgType[dataTypeID || '']?.includes("[]")
                    ? `select unnest(${el.id})::text as id,count(*) from (${optimizedSQL})q group by unnest(${el.id}) limit 100`
                    : `select ${el.id}::text as id,count(*) from (${optimizedSQL})q group by ${el.id} limit 100`;

                const countArr = await pg.queryCache(q, { table });

                if (countArr.timeout) {
                    Object.assign(el, { timeout: countArr.timeout });
                    console.warn("timeout filter", table, el.id);
                }

                const ids = countArr.rows.map((el1) => el1.id);

                const clsData = await getSelectVal({ pg, values: ids, name: el.data });

                const options = countArr.rows.map((cel) => {
                    const data = cls?.arr?.find?.(
                        (c) => c.id?.toString?.() === cel.id?.toString?.()
                    ) || { text: clsData?.[cel.id]?.text || clsData?.[cel.id] || cel.id };
                    return { ...cel, id: cel.id === null ? "null" : cel.id, ...data };
                });
                Object.assign(el, { options });
            })
    );
}