import {
  getMeta, getTemplate, pgClients, getTemplates, yml2json,
} from '@opengis/fastify-table/utils.js';

const table = 'gis.maps';

const columnType = {
  text: 'text',
  date: 'date',
  bool: 'yes/no',
  numeric: 'number',
  integer: 'number',
  'timestamp without time zone': 'date',
  'timestamp with time zone': 'date',
};

export default async function getMap({ params = {}, pg = pgClients.client }, reply) {
  const { columns = [] } = await getMeta({ pg, table }) || {};

  const fields = columns.map(({ name, dataTypeID, title }) => ({ name, type: columnType[pg.pgType?.[dataTypeID] || 'text'], label: title || name }));
  const mapList = getTemplates('map').map(el => el[0]);

  const rows = pg.pk?.['gis.maps'] ? await pg.query(
    `SELECT map_id as id, *  FROM gis.maps where ${params.id ? '$1 in (map_id,map_key)' : '1=1'}`,
    [params.id].filter(Boolean),
  ).then(el => el.rows || []) : [];

  if (params.id && !mapList?.includes(params.id) && !rows[0]) {
    return { status: 404, message: 'map not found' };
  }

  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 || {}) : {};
  const maps = pg.pk?.['gis.maps'] ? await pg.query(
    'SELECT map_id as id, map_key as slug, name  FROM gis.maps where is_active and is_public order by name',
  ).then(el => el.rows || []) : [];

  if (params.id) {
    const map = rows[0] || {};
    const loadTemplate = await getTemplate('map', params.id) || await getTemplate('map', map.map_key);

    const obj = loadTemplate || map;

    const layers = [];

    if (Array.isArray(obj?.ogc) && obj.ogc.length && ['string', 'number'].includes(typeof obj.ogc[0])) {
      await Promise.all(obj.ogc.map(async (layer) => {
        const ogcData = await pg.query('select ogc_service_id as id, url as service_url, * from gis.ogc_service where ogc_service_id=$1', [layer]).then(el => el.rows?.[0]);
        layers.push({
          ...(ogcData || {}), id: layer, /* center: [], bbox: null, filters: [], style: { color: 'red' }, */ visible: !!ogcData, type: 'ogc',
        });
      }));
    }

    if (Array.isArray(obj?.layers) && typeof obj?.layers?.[0] === 'string') {
      await Promise.all(obj.layers.map(async (layer) => {
        const layerData = await getTemplate('layer', layer);
        const serviceData = layerData || await pg.query('select service_id as id, *, st_asgeojson(bbox)::json as bbox, st_asgeojson(center)::json as center from gis.services where service_id=$1', [layer]).then(el => el.rows?.[0]);
        Object.assign(serviceData || {}, { count: totals[serviceData?.source_path || ''] || 0 });
        if (serviceData) { serviceData.style = typeof serviceData.style === 'object' ? serviceData.style : yml2json(serviceData.style); }
        layers.push({ ...(serviceData || {}), id: layer, visible: !!serviceData });
      }));
    }

    return reply.status(200).send({ maps, ...obj, layers });
  }

  if (params.id && !rows.length) {
    return reply.status(404).send('map not found');
  }

  if (params.id) {
    return reply.status(200).send({ ...rows[0], fields });
  }

  return reply.status(200).send({
    rows,
    fields,
  });
}
