/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const { spawn, execSync } = require('child_process');
const fetch = require('fetch-retry')(require('isomorphic-fetch'));
const kinds = require('./kinds/kinds');
const path = require('path');

const RUNTIME_PORT = 8080;
const INIT_RETRY_DELAY_MS = 100;

// https://github.com/apache/incubator-openwhisk/blob/master/docs/reference.md#system-limits
const OPENWHISK_DEFAULTS = {
    timeout: 60*1000,
    memory: 256
};

function execute(cmd, options, verbose) {
    cmd = cmd.replace(/\s+/g, ' ');
    if (verbose) {
        console.log(cmd);
    }
    const result = execSync(cmd, options);
    if (result) {
        return result.toString().trim();
    } else {
        return '';
    }
}

// if value is a function, invoke it with args, otherwise return it as object
// if value is undefined, will return undefined
function resolveValue(value, ...args) {
    if (typeof value === "function") {
        return value(...args);
    } else {
        return value;
    }
}

class OpenWhiskInvoker {
    constructor(actionName, action, options, wskProps, wsk) {
        this.actionName = actionName;
        this.action = action;

        this.kind = options.kind;
        this.image = options.image;
        this.port = options.port;
        this.internalPort = options.internalPort;
        this.command = options.command;
        this.dockerArgs = options.dockerArgs;
        this.verbose = options.verbose;

        // the build path can be separate, if not, same as the source/watch path
        this.sourcePath = options.buildPath || options.sourcePath;
        if (this.sourcePath) {
            this.sourceDir = process.cwd();
            // ensure sourcePath is relative to sourceDir
            this.sourceFile = path.relative(this.sourceDir, this.sourcePath);
        }

        this.main = options.main;

        this.wskProps = wskProps;
        this.wsk = wsk;

        this.containerName = this.asContainerName(`wskdebug-${this.action.name}-${Date.now()}`);
    }

    static async checkIfAvailable() {
        try {
            execute("docker info", {stdio: 'ignore'});
        } catch (e) {
            throw new Error("Docker not running on local system. A local docker environment is required for the debugger.")
        }
    }

    async getImageForKind(kind) {
        try {
            const owSystemInfo = await this.wsk.actions.client.request("GET", "/");
            if (owSystemInfo.runtimes) {
                // transform result into a nice dictionary kind => image
                const runtimes = {};
                for (const set of Object.values(owSystemInfo.runtimes)) {
                    for (const entry of set) {
                        let image = entry.image;
                        // fix for Adobe I/O Runtime reporting incorrect image prefixes
                        image = image.replace("bladerunner/", "adobeapiplatform/");
                        runtimes[entry.kind] = image;
                    }
                }
                return runtimes[kind];

            } else if (this.verbose) {
                console.warn("Could not retrieve runtime images from OpenWhisk, using default image list.");
            }

        } catch (e) {
            if (this.verbose) {
                console.warn("Could not retrieve runtime images from OpenWhisk, using default image list.", e.message);
            }
        }
        return kinds.images[kind];
    }

    async startContainer() {
        const action = this.action;

        // this must run after initial build was kicked off in Debugger.startSourceWatching()
        // so that built files are present

        // kind and image

        // precendence:
        // 1. arguments (this.image)
        // 2. action (action.exec.image)
        // 3. defaults (kinds.images[kind])

        const kind = this.kind || action.exec.kind;

        if (kind === "blackbox") {
            throw new Error("Action is of kind 'blackbox', must specify kind using `--kind` argument.");
        }

        // const runtime = kinds[kind] || {};
        this.image = this.image || action.exec.image || await this.getImageForKind(kind);

        if (!this.image) {
            throw new Error(`Unknown kind: ${kind}. You might want to specify --image.`);
        }

        // debugging instructions
        this.debugKind = kinds.debugKinds[kind] || kind.split(":")[0];
        try {
            this.debug = require(`${__dirname}/kinds/${this.debugKind}/${this.debugKind}`);
        } catch (e) {
            if (this.verbose) {
                console.error(`Cannot find debug info for kind ${this.debugKind}:`, e.message);
            }
            this.debug = {};
        }

        this.debug.internalPort = this.internalPort                      || resolveValue(this.debug.port, this);
        this.debug.port         = this.port         || this.internalPort || resolveValue(this.debug.port, this);

        // ------------------------

        this.debug.command = this.command || resolveValue(this.debug.command, this);

        if (!this.debug.port) {
            throw new Error(`No debug port known for kind: ${kind}. Please specify --port.`);
        }
        if (!this.debug.internalPort) {
            throw new Error(`No debug port known for kind: ${kind}. Please specify --internal-port.`);
        }
        if (!this.debug.command) {
            throw new Error(`No debug command known for kind: ${kind}. Please specify --command.`);
        }

        // limits
        const memory = (action.limits.memory || OPENWHISK_DEFAULTS.memory) * 1024 * 1024;

        // source mounting
        if (this.sourcePath) {
            if (!this.debug.mountAction) {
                console.warn(`Warning: Sorry, mounting sources not yet supported for: ${kind}.`);
                this.sourcePath = undefined;
            }
        }

        const dockerArgsFromKind = resolveValue(this.debug.dockerArgs, this) || "";
        const dockerArgsFromUser = this.dockerArgs || "";

        let showDockerRunOutput = this.verbose;

        try {
            execute(`docker inspect --type=image ${this.image} 2> /dev/null`);
        } catch (e) {
            // make sure the user can see the image download process as part of docker run
            showDockerRunOutput = true;
            console.log(`
+------------------------------------------------------------------------------------------+
| Docker image must be downloaded: ${this.image}
|                                                                                          |
| Note: If you debug in VS Code and it fails with "Cannot connect to runtime process"      |
| due to a timeout, run this command once:                                                 |
|                                                                                          |
|     docker pull ${this.image}
|                                                                                          |
| Alternatively set a higher 'timeout' in the launch configuration, such as 60000 (1 min). |
+------------------------------------------------------------------------------------------+
`);
        }

        if (this.verbose) {
            console.log(`Starting local debug container ${this.name()}`);
        }

        execute(
            `docker run
                -d
                --name ${this.name()}
                --rm
                -m ${memory}
                -p ${RUNTIME_PORT}
                -p ${this.debug.port}:${this.debug.internalPort}
                ${dockerArgsFromKind}
                ${dockerArgsFromUser}
                ${this.image}
                ${this.debug.command}
            `,
            // live stream view for docker image download output
            { stdio: showDockerRunOutput ? "inherit" : null },
            this.verbose
        );

        this.containerRunning = true;

        spawn("docker", ["logs", "-t", "-f", this.name()], {
            stdio: [
                "inherit", // stdin
                global.mochaLogFile || "inherit", // stdout
                global.mochaLogFile || "inherit"  // stderr
            ]
        });
    }

    getSourcePath() {
        return this.sourcePath;
    }

    getImage() {
        return this.image;
    }

    getDebugKind() {
        return this.debugKind;
    }

    getPort() {
        return this.debug.port;
    }

    async init(actionWithCode) {
        let action;
        if (this.sourcePath && this.debug.mountAction) {
            action = resolveValue(this.debug.mountAction, this);

            if (this.verbose) {
                console.log(`Mounting sources onto local debug container: ${this.sourcePath}`);
            }
        } else {
            if (this.verbose) {
                console.log(`Pushing action code to local debug container: ${this.action.name}`);
            }
            action = {
                binary: actionWithCode.exec.binary,
                main:   actionWithCode.exec.main || "main",
                code:   actionWithCode.exec.code,
            };
        }

        const response = await fetch(`${this.url()}/init`, {
            method: "POST",
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                value: action
            }),
            retries: this.timeout() / INIT_RETRY_DELAY_MS,
            retryDelay: INIT_RETRY_DELAY_MS
        });

        if (response.status === 502) {
            const body = await response.json();
            throw new Error("Could not initialize action code on local debug container:\n\n" + body.error);
        }
    }

    async run(args, activationId) {
        const response = await fetch(`${this.url()}/run`, {
            method: "POST",
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                value: args,

                api_host        : this.wskProps.apihost,
                api_key         : this.wskProps.api_key,
                namespace       : this.wskProps.namespace,
                action_name     : `/${this.wskProps.namespace}/${this.actionName}`,
                activation_id   : activationId,
                deadline        : `${Date.now() + this.timeout()}`,
                allow_concurrent: "true"
            })
        });

        return response.json();
    }

    async stop() {
        if (this.containerRunning) {
            if (this.verbose) {
                console.log("Stopping local debug container");
            }
            execute(`docker kill ${this.name()}`);
        }
    }

    name() {
        return this.containerName;
    }

    url() {
        if (!this.containerURL) {
            // ask docker for the exposed IP and port of the RUNTIME_PORT on the container
            const host = execute(`docker port ${this.name()} ${RUNTIME_PORT}`);
            this.containerURL = `http://${host}`;
        }
        return this.containerURL;
    }

    timeout() {
        return this.action.limits.timeout || OPENWHISK_DEFAULTS.timeout;
    }

    asContainerName(name) {
        // docker container names are restricted to [a-zA-Z0-9][a-zA-Z0-9_.-]*

        // 1. replace special characters with dash
        name = name.replace(/[^a-zA-Z0-9_.-]+/g, '-');
        // 2. leading character is more limited
        name = name.replace(/^[^a-zA-Z0-9]+/g, '');
        // 3. (nice to have) remove trailing special chars
        name = name.replace(/[^a-zA-Z0-9]+$/g, '');

        return name;
    }
}

module.exports = OpenWhiskInvoker;
