import {
  config, pgClients, yml2json, getTemplates, getTemplate,
} from '@opengis/fastify-table/utils.js';
import getPermissions from '../../permissions/controllers/utils/get.permissions.js';

export default async function layerList({
  pg = pgClients.client, query = {}, user = {},
}, reply) {
  const { sql } = query;
  const layers = getTemplates('layer');
  const files = Promise.all(layers.map(async (el) => {
    const layer = await getTemplate('layer', el[0]);
    return layer;
  }));

  if (!pg.pk?.['gis.services'] && !pg.pk?.['gis.ogc_service'] && !pg.pk?.['gis.rasters'] && !pg.pk?.['gis.cartocss']) {
    return files;
    // return reply.status(404).send('services table not found');
  }

  const { all_layers, layer_list } = (user.uid) ? await getPermissions({ pg, uid: user.uid }) : { all_layers: false, layer_list: [] };

  const whereServices = (all_layers === true) ? '1=1'
    : (user.uid && !all_layers) ? '( s.is_public or s.service_id = any($1))'
      : 'is_public';

  const whereOgcServices = (all_layers === true) ? '1=1'
    : (user.uid && !all_layers) ? '( s.ispublic or s.ogc_service_id = any($1))'
      : 'ispublic';

  const whereRasters = (all_layers === true) ? '1=1'
    : (user.uid && !all_layers) ? '(s.is_public or s.raster_id = any($1))'
      : 'is_public';

  const whereCartocss = (all_layers === true) ? '1=1'
    : (user.uid && !all_layers) ? '(s.is_public or s.cartocss_id = any($1))'
      : 'is_public';
  const q = `
   select * from 
   (
    select service_id as id, name, category, style, bbox::box2d as extent, st_asgeojson(bbox)::json as geom, coalesce('/api/vtile/'||service_id||'/ua/{z}/{x}/{y}.vmt',null) as url, coalesce(service_type, 'vtile') as service, group_id,
        popup, card, filters, source_path
    from gis.services s where is_active and
    ${whereServices}
    union all 
    select ogc_service_id as id, name, category, null as style, geom::box2d as extent, st_asgeojson(geom)::json as geom, url, 'ogc' as service, group_id,
        null as popup, null as card, null as filters, table_name as source_path
    from gis.ogc_service s where enabled and
    ${whereOgcServices}
    union all 
    select raster_id as id, name, null as category, null as style, geom::box2d as extent, st_asgeojson(geom)::json as geom, 
    coalesce('/api/gis-rtile/'||rtrim(
                            replace(
                                replace(
                                    encode(source_path::bytea, 'base64'),
                                    '+', '-'
                                ),
                                '/', '_'
                            ),
                            '='
                        )||'/{z}/{x}/{y}.png',null) as url, 'raster' as service, group_id,
        null as popup, null as card, null as filters, source_path
    from gis.rasters s where is_active and
    ${whereRasters}
    union all 
    select cartocss_id as id, name, null as category, style, geom::box2d as bbox, st_asgeojson(geom)::json as geom,
    coalesce('/api/gis-rtile/'||cartocss_id||'/{z}/{x}/{y}.png',null) as url, 'cartocss' as service, group_id,
        null as popup, null as card, null as filters, null as source_path
    from gis.cartocss s where enabled and
    ${whereCartocss}
     )q order by q.name
    `;

  if (user.uid && sql) return q;

  const rows = await pg.query(q, (user.uid && !all_layers) ? [layer_list] : []).then(el => el.rows || []);

  const totals = pg.queryCache ? await pg.queryCache('select json_object_agg(oid::regclass, reltuples) from pg_class')
    .then(el => el.rows?.[0]?.json_object_agg || {}) : {};
  rows.filter(row => row.source_path).forEach(row => Object.assign(row, { count: totals[row.source_path] || 0 }));

  const groupIds = rows.map(el => el.group_id).filter(Boolean);
  const groupNames = groupIds.length ? await pg.query('select json_object_agg(group_id,group_name) from gis.group_list where group_id=any($1)', [groupIds]).then(el => el.rows?.[0]?.json_object_agg || {}) : {};
  rows.filter(el => el.group_id).forEach(row => Object.assign(row, { group_name: groupNames[row.group_id] }));

  if (!rows.length) {
    return reply.status(200).send([]);
  }

  // parse service style
  rows.forEach(row => Object.assign(row, { style: row.style && ['vtile', 'geojson'].includes(row.service) ? yml2json(row.style) : row.style }));
  // parse extent string to number[]
  rows.filter(row => row.extent).forEach(row => Object.assign(row, {
    extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
      ?.replace?.(/ /g, ',')
      ?.split?.(','),
  }));

  // return files;

  return reply.status(200).send(rows.concat(files));
}
