"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.frontendBuildPath = exports.readConfig = exports.isInHeroku = exports.isInGoogleAppEngine = exports.Environment = void 0;
const fs_1 = require("fs");
const util_1 = require("util");
const path_1 = require("path");
const common_stuff_1 = require("common-stuff");
const zod_1 = require("zod");
var Environment;
(function (Environment) {
    Environment["Production"] = "production";
    Environment["Development"] = "development";
})(Environment = exports.Environment || (exports.Environment = {}));
const configSchema = zod_1.z.object({
    /**
     * Server host.
     *
     * Default: `0.0.0.0`
     */
    host: zod_1.z.string(),
    /**
     * Server port.
     *
     * Default: `env.PORT` or 3000
     */
    port: zod_1.z.number(),
    /**
     * Project environment.
     *
     * Default: `production`
     */
    environment: zod_1.z.nativeEnum(Environment),
    /**
     * Logging configuration.
     *
     * Default: `console`
     */
    logging: zod_1.z.object({
        transports: zod_1.z.array(zod_1.z.union([
            zod_1.z.object({
                type: zod_1.z.literal('console'),
            }),
            zod_1.z.object({
                type: zod_1.z.literal('loggly'),
                subdomain: zod_1.z.string(),
                token: zod_1.z.string(),
                tags: zod_1.z.array(zod_1.z.string()).optional(),
            }),
        ])),
        /**
         * Logging level.
         *
         * Default: `info`
         */
        level: zod_1.z.enum(['debug', 'info', 'warn', 'error']),
    }),
    /**
     * Torrent client settings
     */
    torrents: zod_1.z.object({
        path: zod_1.z.string(),
        /**
         * Delete torrent data if it is inactive for X seconds.
         *
         * Default: `3600`
         */
        ttl: zod_1.z.number(),
        /**
         * Load default trackers list & use it for each torrents.
         *
         * Default: `true`
         */
        useDefaultTrackers: zod_1.z.boolean(),
        /**
         * Additional trackers (`tr` parameter) which will be appended to each torrent.
         *
         * Default: `[]`
         */
        announce: zod_1.z.array(zod_1.z.string()),
        /**
         * Web Seed (`ws` parameter) which will be appended to each torrent.
         *
         * Default: `[]`
         */
        urlList: zod_1.z.array(zod_1.z.string()),
        /**
         * Peer addresses (`x.pe` parameter).
         *
         * Default: `[]`
         */
        peerAddresses: zod_1.z.array(zod_1.z.string()),
    }),
    /**
     * Security settings
     */
    security: zod_1.z.object({
        /**
         * Stream API (`/stream/:torrent`) settings
         */
        streamApi: zod_1.z.object({
            /**
             * Protect stream API with [JSON Web Token](https://jwt.io/).
             *
             * If `apiKey` is not set, it can also be used as API key (`authorization`: `bearer ${apiKey}`).
             *
             * Default: `undefined`
             */
            key: zod_1.z.string().optional(),
            /**
             * The maximum allowed age for tokens to still be valid.
             * It is expressed in seconds or a string describing a time span [zeit/ms](https://github.com/vercel/ms)
             *
             * Default: `6h`
             */
            maxAge: zod_1.z.string(),
        }),
        /**
         * Serve frontend static files
         *
         * Default: environment === 'production'
         */
        frontendEnabled: zod_1.z.boolean(),
        /**
         * Enable API
         *
         * Default: true
         */
        apiEnabled: zod_1.z.boolean(),
        /**
         * Protect API with key. It should be passed to headers to access the API (`authorization`: `bearer ${apiKey}`).
         *
         * If `streamApi` doesn't have a separate key, `apiKey` can be used as JSON Web Token.
         *
         * Default: undefined
         */
        apiKey: zod_1.z.string().optional(),
    }),
    /**
     * Get ip from `X-Forwarded-*` header.
     *
     * Default: true if inside App Engine or Heroku else false
     */
    trustProxy: zod_1.z.boolean(),
});
exports.isInGoogleAppEngine = process.env.GAE_APPLICATION ? true : false;
exports.isInHeroku = process.env._ ? process.env._.toLowerCase().includes('heroku') : false;
const parsedEnv = common_stuff_1.convertToNested(process.env, {
    separator: '__',
    transformKey: common_stuff_1.camelCase,
});
const defaultConfig = {
    host: parsedEnv.host || '0.0.0.0',
    port: parsedEnv.port || 3000,
    environment: parsedEnv.nodeEnv === Environment.Development
        ? Environment.Development
        : Environment.Production,
    trustProxy: !!parsedEnv.trustProxy || exports.isInGoogleAppEngine || exports.isInHeroku,
    logging: {
        transports: [
            {
                type: 'console',
            },
        ],
        level: 'info',
    },
    torrents: {
        path: '/tmp/torrent-stream-server',
        ttl: 60 * 60,
        useDefaultTrackers: true,
        announce: [],
        urlList: [],
        peerAddresses: [],
    },
    security: {
        streamApi: {
            maxAge: '6h',
        },
        apiKey: parsedEnv.apiKey || undefined,
        frontendEnabled: true,
        apiEnabled: true,
    },
};
async function readConfig(path) {
    try {
        return configSchema.parse(common_stuff_1.merge(common_stuff_1.merge(defaultConfig, path ? JSON.parse(await util_1.promisify(fs_1.readFile)(path, { encoding: 'utf8' })) : {}), parsedEnv.config || {}));
    }
    catch (err) {
        if (err instanceof zod_1.z.ZodError) {
            const errors = err.errors.map((v) => `${v.message} @ ${v.path.join('.')}`);
            throw Error(`Configuration error: ${errors.join(', ')}`);
        }
        throw Error(`Configuration error: ${err}`);
    }
}
exports.readConfig = readConfig;
/**
 * Frontend package path to build directory
 */
exports.frontendBuildPath = path_1.resolve(__dirname, '../frontend/build');
