///|
/// Options for `moonohos init`.
pub(all) struct InitOptions {
  /// Native module and HAR module name, e.g. `textkit`.
  name : String
  /// MoonBit package, e.g. `alice/textkit`.
  package_name : String
  /// Workspace path from the project to the `ohos` platform module, if local.
  ohos : String?
}

///|
pub fn valid_module_name(name : String) -> Bool {
  if name.is_empty() || name.length() > 32 {
    return false
  }
  for index, ch in name {
    if !(ch >= 'a' && ch <= 'z') &&
      !(index > 0 && (ch == '_' || (ch >= '0' && ch <= '9'))) {
      return false
    }
  }
  true
}

///|
/// Relative path from directory `from` to `to`; both absolute with `/`.
pub fn relative_path(from : String, to : String) -> String {
  let a = from.split("/").filter(s => s != "").map(s => s.to_owned()).to_array()
  let b = to.split("/").filter(s => s != "").map(s => s.to_owned()).to_array()
  let mut common = 0
  while common < a.length() &&
        common < b.length() &&
        a[common].to_lower() == b[common].to_lower() {
    common += 1
  }
  let parts : Array[String] = []
  for _ in common.. String {
  let owner = options.package_name
    .split("/")
    .head()
    .unwrap_or("moonohos")
    .to_owned()
  "@" + owner.to_lower() + "/" + options.name.replace_all(old="_", new="-")
}

///|
/// Files of a new MoonOHOS project: a MoonBit library, its bridge manifest and
/// a Hvigor project whose HAR module will carry the built libraries.
pub fn init_files(
  options : InitOptions,
) -> Array[(String, String)] raise ConfigError {
  if !valid_module_name(options.name) {
    raise Invalid("init: name must match [a-z][a-z0-9_]{0,31}: " + options.name)
  }
  let parts = options.package_name.split("/").to_array()
  if parts.length() != 2 ||
    !identifier(parts[0].to_owned()) ||
    !identifier(parts[1].to_owned()) {
    raise Invalid("init: package must be owner/name: " + options.package_name)
  }
  let name = options.name
  let module_dir = "core"
  let members = ["  \"./" + module_dir + "\",\n"]
  if options.ohos is Some(path) {
    members.push("  \"" + path + "\",\n")
  }
  let template = (text : String) => {
    text
    .replace_all(old="__NAME__", new=name)
    .replace_all(old="__PACKAGE__", new=options.package_name)
    .replace_all(old="__HAR__", new=har_name(options))
    .replace_all(old="__VERSION__", new=moonohos_version())
  }
  let files : Array[(String, String)] = [
    ("moon.work", "members = [\n" + members.join("") + "]\n"),
    (
      "moonohos.json",
      template(
        (
          #|{
          #|  "version": 2,
          #|  "module": "core",
          #|  "package": "__PACKAGE__",
          #|  "nativeModule": "__NAME__",
          #|  "workspace": "moon.work",
          #|  "functions": [
          #|    {"name": "greet", "params": [{"name": "name", "type": "String"}], "return": "String"},
          #|    {"name": "count_words", "params": [{"name": "text", "type": "String"}], "return": "Int", "async": true, "raises": true}
          #|  ]
          #|}
          #|
        ),
      ),
    ),
    (
      "core/moon.mod",
      template(
        (
          #|name = "__PACKAGE__"
          #|
          #|version = "0.1.0"
          #|
          #|preferred_target = "native"
          #|
          #|import {
          #|  "shop1111/moonohos_ohos@__VERSION__",
          #|}
          #|
        ),
      ),
    ),
    (
      "core/moon.pkg",
      (
        #|import {
        #|  "shop1111/moonohos_ohos/hilog",
        #|  "shop1111/moonohos_ohos/task",
        #|}
        #|
      ),
    ),
    (
      "core/lib.mbt",
      template(
        (
          #|///|
          #|/// Synchronous export: runs on the calling ArkTS thread.
          #|pub fn greet(name : String) -> String {
          #|  "Hello, " + name + " from MoonBit"
          #|}
          #|
          #|///|
          #|/// Async export: runs on a Node-API worker thread and polls cancellation.
          #|pub fn count_words(text : String) -> Int raise @task.Cancelled {
          #|  let mut count = 0
          #|  let mut inside = false
          #|  for index, ch in text {
          #|    if index % 4096 == 0 {
          #|      @task.check()
          #|    }
          #|    let space = ch == ' ' || ch == '\n' || ch == '\t'
          #|    if !space && !inside {
          #|      count += 1
          #|    }
          #|    inside = !space
          #|  }
          #|  let logger = @hilog.Logger::new(0x4d4f, "__NAME__") catch { _ => panic() }
          #|  logger.info("count_words " + count.to_string())
          #|  count
          #|}
          #|
        ),
      ),
    ),
    (
      "core/lib_test.mbt",
      (
        #|///|
        #|test "exports" {
        #|  assert_eq(greet("ArkTS"), "Hello, ArkTS from MoonBit")
        #|  assert_eq(count_words("one two\nthree"), 3)
        #|}
        #|
      ),
    ),
    (
      ".gitignore",
      (
        #|_build/
        #|.mooncakes/
        #|**/build/
        #|**/oh_modules/
        #|**/.hvigor/
        #|**/oh-package-lock.json5
        #|**/BuildProfile.ets
        #|harmony/*/libs/
        #|harmony/*/src/main/cpp/types/
        #|harmony/*/src/main/ets/generated/
        #|*.har
        #|
      ),
    ),
    (
      "README.md",
      template(
        (
          #|# __NAME__
          #|
          #|MoonBit native module for HarmonyOS, generated by MoonOHOS __VERSION__.
          #|
          #|```powershell
          #|moonohos build --sdk '\sdk' --out _build/dist
          #|moonohos har --dist _build/dist --module harmony/__NAME__ --assemble --deveco ''
          #|```
          #|
          #|The HAR is written to `harmony/__NAME__/build/default/outputs/default/__NAME__.har`.
          #|An application adds `"__HAR__": "file:/__NAME__.har"` to its
          #|`oh-package.json5` and imports it:
          #|
          #|```typescript
          #|import native, { CancelToken } from '__HAR__';
          #|const token: CancelToken = native.createCancelToken();
          #|const words: number = await native.count_words('a b c', token);
          #|```
          #|
        ),
      ),
    ),
    (
      "harmony/build-profile.json5",
      template(
        (
          #|{
          #|  "app": {
          #|    "products": [{"name": "default", "compatibleSdkVersion": "26.0.0", "targetSdkVersion": "26.0.0", "runtimeOS": "HarmonyOS"}],
          #|    "buildModeSet": [{"name": "debug"}, {"name": "release"}]
          #|  },
          #|  "modules": [{"name": "__NAME__", "srcPath": "./__NAME__"}]
          #|}
          #|
        ),
      ),
    ),
    (
      "harmony/oh-package.json5",
      template(
        "{\"modelVersion\": \"5.0.0\", \"name\": \"__NAME__-har-project\", \"version\": \"0.1.0\", \"dependencies\": {}, \"devDependencies\": {}}\n",
      ),
    ),
    (
      "harmony/hvigorfile.ts", "import { appTasks } from '@ohos/hvigor-ohos-plugin';\nexport default { system: appTasks, plugins: [] };\n",
    ),
    (
      "harmony/hvigor/hvigor-config.json5", "{\"modelVersion\": \"5.0.0\", \"dependencies\": {}, \"execution\": {}, \"logging\": {\"level\": \"info\"}, \"nodeOptions\": {}}\n",
    ),
    (
      "harmony/AppScope/app.json5",
      template(
        "{\"app\": {\"bundleName\": \"com.moonohos.__NAME__\", \"vendor\": \"MoonOHOS\", \"versionCode\": 1000000, \"versionName\": \"0.1.0\", \"icon\": \"$media:app_icon\", \"label\": \"$string:app_name\"}}\n",
      ),
    ),
    (
      "harmony/AppScope/resources/base/element/string.json",
      template(
        "{\"string\": [{\"name\": \"app_name\", \"value\": \"__NAME__\"}]}\n",
      ),
    ),
    (
      "harmony/AppScope/resources/base/media/app_icon.svg", "\n",
    ),
    (
      "harmony/__NAME__/oh-package.json5".replace_all(old="__NAME__", new=name),
      template(
        "{\n  \"name\": \"__HAR__\",\n  \"version\": \"0.1.0\",\n  \"description\": \"MoonBit native module __NAME__\",\n  \"main\": \"Index.ets\",\n  \"license\": \"Apache-2.0\",\n  \"dependencies\": {\n    \"lib__NAME__.so\": \"file:./src/main/cpp/types/lib__NAME__\"\n  }\n}\n",
      ),
    ),
    (
      "harmony/__NAME__/Index.ets".replace_all(old="__NAME__", new=name),
      (
        #|// Public entry of the HAR; `moonohos har` regenerates src/main/ets/generated/Native.ets.
        #|import native from './src/main/ets/generated/Native';
        #|
        #|export * from './src/main/ets/generated/Native';
        #|export default native;
        #|
      ),
    ),
    (
      "harmony/__NAME__/build-profile.json5".replace_all(
        old="__NAME__",
        new=name,
      ),
      "{\"apiType\": \"stageMode\", \"buildOption\": {}, \"targets\": [{\"name\": \"default\"}]}\n",
    ),
    (
      "harmony/__NAME__/hvigorfile.ts".replace_all(old="__NAME__", new=name),
      "import { harTasks } from '@ohos/hvigor-ohos-plugin';\nexport default { system: harTasks, plugins: [] };\n",
    ),
    (
      "harmony/__NAME__/src/main/module.json5".replace_all(
        old="__NAME__",
        new=name,
      ),
      template(
        "{\"module\": {\"name\": \"__NAME__\", \"type\": \"har\", \"deviceTypes\": [\"phone\", \"tablet\", \"2in1\"]}}\n",
      ),
    ),
  ]
  files
}