/**
 * Copyright (c) 2020 Gitpod GmbH. All rights reserved.
 * Licensed under the GNU Affero General Public License (AGPL).
 * See License-AGPL.txt in the project root for license information.
 */

import { injectable } from "inversify";
import * as yaml from "js-yaml";
import * as Ajv from "ajv";
import { log } from './util/logging';
import { WorkspaceConfig, PortRangeConfig } from "./protocol";

export type MaybeConfig = WorkspaceConfig | undefined

const schema = require('../data/gitpod-schema.json');
const validate = new Ajv().compile(schema);
const defaultParseOptions = {
    acceptPortRanges: false,
};

export interface ParseResult {
    config: WorkspaceConfig
    parsedConfig?: WorkspaceConfig
    validationErrors?: string[]
}

@injectable()
export class GitpodFileParser {

    public parse(content: string, parseOptions = {}, defaultConfig: WorkspaceConfig = {}): ParseResult {
        const options = {
           ...defaultParseOptions,
           ...parseOptions,
        };
        try {
            const parsedConfig = yaml.safeLoad(content) as any;
            validate(parsedConfig);
            const validationErrors = validate.errors ? validate.errors.map( e => e.message || e.keyword ) : undefined;
            if (validationErrors && validationErrors.length > 0) {
                return {
                    config: defaultConfig,
                    parsedConfig,
                    validationErrors
                };
            }
            const overrides = {} as any;
            if (!options.acceptPortRanges && Array.isArray(parsedConfig.ports)) {
                overrides.ports = parsedConfig.ports.filter((port: any) => !PortRangeConfig.is(port));
            }
            return {
                config: {
                    ... defaultConfig,
                    ... parsedConfig,
                    ... overrides,
                },
                parsedConfig
            };
        } catch (err) {
            log.error('Unparsable Gitpod configuration', err, { content });
            return {
                config: defaultConfig,
                validationErrors: ['Unparsable Gitpod configuration: ' + err.toString()]
            };
        }
    }
}
