import { TileSetType } from '@basemaps/config';
import { Env, toQueryString } from '@basemaps/shared';
import { fsa } from '@chunkd/fs';
import { HttpHeader, LambdaHttpResponse } from '@linzjs/lambda';
import { URL } from 'url';
import { NotFound, NotModified } from '../util/response.js';
import { Validate } from '../util/validate.js';
import { Etag } from '../util/etag.js';
import { ConfigLoader } from '../util/config.loader.js';
import { GoogleTms, ImageFormat, TileMatrixSets } from '@basemaps/geo';
/**
 * Convert relative URLS into a full hostname url
 * @param url possible url to update
 * @param apiKey ApiKey to append with ?api= if required
 * @returns Updated Url or empty string if url is empty
 */
export function convertRelativeUrl(url, apiKey, config) {
    var _a;
    if (url == null)
        return '';
    const host = (_a = Env.get(Env.PublicUrlBase)) !== null && _a !== void 0 ? _a : '';
    if (!url.startsWith('/'))
        return url; // Not relative ignore
    const fullUrl = new URL(fsa.join(host, url));
    if (apiKey)
        fullUrl.searchParams.set('api', apiKey);
    if (config)
        fullUrl.searchParams.set('config', config);
    return fullUrl.toString().replace(/%7B/g, '{').replace(/%7D/g, '}');
}
/**
 * Create a new style json that has absolute urls to the current host and  API Keys where required
 * @param style style to update
 * @param apiKey api key to inject
 * @returns new stylejson
 */
export function convertStyleJson(style, apiKey, config) {
    var _a;
    const sources = JSON.parse(JSON.stringify(style.sources));
    for (const [key, value] of Object.entries(sources)) {
        if (value.type === 'vector') {
            value.url = convertRelativeUrl(value.url, apiKey, config);
        }
        else if (value.type === 'raster' && Array.isArray(value.tiles)) {
            for (let i = 0; i < value.tiles.length; i++) {
                value.tiles[i] = convertRelativeUrl(value.tiles[i], apiKey, config);
            }
        }
        sources[key] = value;
    }
    return {
        version: 8,
        id: style.id,
        name: style.name,
        sources,
        layers: style.layers,
        metadata: (_a = style.metadata) !== null && _a !== void 0 ? _a : {},
        glyphs: convertRelativeUrl(style.glyphs, undefined, config),
        sprite: convertRelativeUrl(style.sprite, undefined, config),
    };
}
export async function tileSetToStyle(req, tileSet, apiKey) {
    var _a, _b, _c;
    const tileMatrix = TileMatrixSets.find((_a = req.query.get('tileMatrix')) !== null && _a !== void 0 ? _a : GoogleTms.identifier);
    if (tileMatrix == null)
        return new LambdaHttpResponse(400, 'Invalid tile matrix');
    const [tileFormat] = (_b = Validate.getRequestedFormats(req)) !== null && _b !== void 0 ? _b : [ImageFormat.Webp];
    if (tileFormat == null)
        return new LambdaHttpResponse(400, 'Invalid image format');
    const configLocation = ConfigLoader.extract(req);
    const query = toQueryString({ config: configLocation, api: apiKey });
    const tileUrl = fsa.join((_c = Env.get(Env.PublicUrlBase)) !== null && _c !== void 0 ? _c : '', `/v1/tiles/${tileSet.name}/${tileMatrix.identifier}/{z}/{x}/{y}.${tileFormat}${query}`);
    const styleId = `basemaps-${tileSet.name}`;
    const style = {
        version: 8,
        sources: { [styleId]: { type: 'raster', tiles: [tileUrl], tileSize: 256 } },
        layers: [{ id: styleId, type: 'raster', source: styleId }],
    };
    const data = Buffer.from(JSON.stringify(style));
    const cacheKey = Etag.key(data);
    if (Etag.isNotModified(req, cacheKey))
        return NotModified();
    const response = new LambdaHttpResponse(200, 'ok');
    response.header(HttpHeader.ETag, cacheKey);
    response.header(HttpHeader.CacheControl, 'no-store');
    response.buffer(data, 'application/json');
    req.set('bytes', data.byteLength);
    return response;
}
export async function styleJsonGet(req) {
    const apiKey = Validate.apiKey(req);
    const styleName = req.params.styleName;
    // Get style Config from db
    const config = await ConfigLoader.load(req);
    const dbId = config.Style.id(styleName);
    const styleConfig = await config.Style.get(dbId);
    if (styleConfig == null) {
        // Were we given a tileset name instead, generated
        const tileSet = await config.TileSet.get(config.TileSet.id(styleName));
        if (tileSet == null)
            return NotFound();
        if (tileSet.type !== TileSetType.Raster)
            return NotFound();
        return tileSetToStyle(req, tileSet, apiKey);
    }
    // Prepare sources and add linz source
    const style = convertStyleJson(styleConfig.style, apiKey, ConfigLoader.extract(req));
    const data = Buffer.from(JSON.stringify(style));
    const cacheKey = Etag.key(data);
    if (Etag.isNotModified(req, cacheKey))
        return NotModified();
    const response = new LambdaHttpResponse(200, 'ok');
    response.header(HttpHeader.ETag, cacheKey);
    response.header(HttpHeader.CacheControl, 'no-store');
    response.buffer(data, 'application/json');
    req.set('bytes', data.byteLength);
    return response;
}
//# sourceMappingURL=tile.style.json.js.map