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

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 getServices({ params = {}, pg = pgClients.client }, reply) {
  const t = await getTemplate('layer', params.id);
  if (t) return t;
  if (!pg.tlist.includes('gis.services')) return { status: 404, message: 'not found' };
  const rows = await pg.query(`
        SELECT 
            service_id, service_key, name, description, keywords, category, holder, group_id, b.group_name, service_type, card_mode,
            source_type, service_url, source_path, query, geom_type, geometry_column, sql_list, attributes, filters, 
            popup, style, legend, card, srid, bbox::box2d as extent, st_asgeojson(bbox)::json as bbox, st_asgeojson(center)::json as center, is_active as enabled, is_public, is_active, is_downloadable, metadata, 
            metadata_url, thumbnail_url, created_by, updated_by, updated_at, created_at, template 
        FROM gis.services a
        left join lateral (select group_name from gis.group_list where group_id=a.group_id)b on 1=1
        where ${params.id ? 'service_id=$1' : '1=1'}
    `, [params.id].filter(Boolean)).then(el => el.rows || []);

  if (params.id && !rows.length) {
    return reply.status(404).send('service 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 || {}) : {};

  if (params.id) {
    const html = await pg.query('select body from admin.templates where template_id=$1', [params.id]).then(el => el.rows?.[0]?.body);
    Object.assign(rows[0], { html });
  }

  rows.filter(row => row.source_path).forEach(row => {
    Object.assign(row, { count: totals[row.source_path] || 0 });
  });

  const { columns = [] } = await getMeta({ pg, table: rows[0].source_path }) || {};

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

  const noCenterIds = rows.filter(row => !row.center && row.bbox).map(row => row.service_id);

  const centers = noCenterIds.length ? await pg.query('SELECT json_object_agg(service_id, st_pointonsurface(bbox)::json) FROM gis.services where service_id=any($1)', [noCenterIds].filter(Boolean)).then(el => el.rows?.[0]?.json_object_agg || {}) : {};

  await Promise.all(rows.filter(row => centers[row.service_id]).map(async (row) => {
    // console.log('update service center', row.service_id, JSON.stringify(centers[row.service_id]));
    await dataUpdate({
      pg, id: row.service_id, table: 'gis.services', data: { center: centers[row.service_id] },
    });
    Object.assign(row, { center: centers[row.service_id] });
  }));

  rows.forEach(row => Object.assign(row, {
    center: row.center?.coordinates,
    style: row.style ? yml2json(row.style) : undefined,
  }));
  rows.filter(row => row.extent).forEach(row => Object.assign(row, {
    extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
      ?.replace?.(/ /g, ',')
      ?.split?.(','),
  }));

  rows.filter(row => row.filters).forEach(row => Object.assign(row, {
    filters: row.filters.map(filter => ({ ...filter, api: `/api/suggest/${row.source_path}:${filter.name}${filter.data && filter.name !== filter.data ? `?sel=${filter.data}` : ''}` })),
  }));

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

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