/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * This source file is part of the Cangjie project, licensed under Apache-2.0
 * with Runtime Library Exception.
 *
 * See https://cangjie-lang.cn/pages/LICENSE for license information.
 */

import std.process.*
import std.io.*
import std.fs.*
import std.convert.*
import std.env.*

@When[os == "Windows"]
func getPythonCommand(): String {
    if (let Some(pyCommand) <- getPythonCommandFromEnv()){
        return pyCommand
 	}
    if(let Some(devecoPyCommand) <- getVariable("DEVECO_OH_NATIVE_HOME")){
        return devecoPyCommand + "/llvm/python3/bin/python3.11.exe"
    }
    throw Exception("Could not find 'python3' or 'python' in your system's PATH. Please ensure Python is installed and added to your environment variables!")
}

@When[os != "Windows"]
func getPythonCommand(): String {
    getPythonCommandFromEnv() ?? throw Exception(
        "Could not find 'python3' or 'python' in your system's PATH. Please ensure Python is installed and added to your environment variables!")
}

@When[os == "Windows"]
let isWin = true

@When[os != "Windows"]
let isWin = false

func getPythonCommandFromEnv(): ?String {
    let commands = ["python3", "python"];
    for (command in commands) {
        try {
            if (execute(command, "--version") == 0) {
                return command
            }
        } catch (_: Exception) {
            continue
        }
    }
    return None
}

func ensurePsutilInstalled(pyCommand: String): Unit {
    try {
        if (execute(pyCommand, "-c", "import psutil") != 0) {
            println("psutil library not found, installing...")
            if (isWin) {
                execute(pyCommand, "-m", "pip", "install", "psutil", "--timeout", "10", "--retries", "0")
            } else {
                execute("timeout", "-k", "0s", "15s", pyCommand, "-m", "pip", "install", "psutil", "--timeout", "10", "--retries", "0")
            }
            println("psutil installed successfully")
        }
    } catch (e: Exception) {}
}

func checkBuildTools(): Unit {
    // Check CMake
    var found = false
    try {
        if (execute("cmake", "--version") == 0) {
            found = true
        }
    } catch (_: Exception) {}
    if (!found) {
        throw Exception("Could not find 'cmake' in your system's PATH. Please ensure CMake is installed and added to your environment variables!")
    }
    found = false
    // Check Ninja
    try {
        if (execute("ninja", "--version") == 0) {
            found = true
        }
    } catch (_: Exception) {}
    if (!found) {
        throw Exception("Could not find 'ninja' in your system's PATH. Please ensure Ninja is installed and added to your environment variables!")
    }
    found = false
    
    // Check C/C++ compiler
    let ccCommands = ["gcc", "clang", "cc"]
    for (command in ccCommands) {
        try {
            if (execute(command, "--version") == 0) {
                found = true
                break
            }
        } catch (_: Exception) {
            continue
        }
    }
    if (!found) {
        throw Exception("Could not find C compiler (gcc/clang/cc) in your system's PATH. Please ensure a C compiler is installed!")
    }
}

main(): Int64 {
    // Check all required build tools first
    checkBuildTools()
    
    let pyCommand: String = getPythonCommand()
    match (getCommandLine()[1]) {
        case "pre-build" =>
            ensurePsutilInstalled(pyCommand)
            stagePreBuild(pyCommand)              
        case "post-build" => stagePostBuild(pyCommand)
        case "pre-clean" => stagePreClean(pyCommand)
        case _ => 0
    }
}

public func stagePreBuild(pyCommand: String): Int64 {
    return execute(pyCommand, "cjpm_build.py", "build", "--build-stage", "preBuild")
}

public func stagePostBuild(pyCommand: String): Int64 {
    return execute(pyCommand, "cjpm_build.py", "build", "--build-stage", "postBuild")
}

public func stagePreClean(pyCommand: String): Int64 {
    return execute(pyCommand, "cjpm_build.py", "clean")
}