/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed 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.
 */

import { execSync } from "child_process"
import { readdirSync, readFileSync, statSync } from "fs"
import { writeFileSync } from "node:fs"
import * as path from "node:path"

type RecursiveStrings = string | RecursiveStrings[]
export function flat(xs:RecursiveStrings): string[] {
    if (typeof xs === 'string') {
        return [xs]
    }
    return xs.flatMap(x => flat(x))
}
export function over<T>(x:T|undefined, f:(x:T) => string[]): string[] {
    if (x === undefined) {
        return []
    }
    return f(x)
}

export function scan(dir:string): string[] {
    return statSync(dir).isDirectory()
        ? readdirSync(dir).flatMap(file => scan(path.join(dir, file)))
        : [dir]
}

interface RunContext {
    exec: (command:RecursiveStrings) => void
    query: (command:RecursiveStrings) => string
    cd: (dir:string) => void
}
export function run(runner:(ctx:RunContext) => void) {
    let cwd = process.cwd()
    runner({
        exec: (command) => {
            const flatArgs = flat(command)
            execSync(flatArgs.join(' '), { cwd, stdio: 'inherit' })
        },
        query: (command) => {
            const flatArgs = flat(command)
            return execSync(flatArgs.join(' '), { cwd }).toString('utf-8')
        },
        cd: (dir) => {
            cwd = dir
        }
    })
}

const TEMPLATE_DIR = path.resolve(__dirname, '..', 'template')
export function installTemplate(name:string, installPath:string, replacements:Map<string, string>) {
    let content = readFileSync(path.join(TEMPLATE_DIR, name + '.template'), 'utf-8')
    replacements.forEach((val, key) => {
        content = content.replaceAll('%' + key + '%', val)
    })
    writeFileSync(installPath, content, 'utf-8')
}

export function withCWD<T>(cwd:string, op:() => T): T {
    const current = process.cwd()
    process.chdir(cwd)
    const r = op()
    process.chdir(current)
    return r
}