/*
 * Copyright (c) 2026 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 fs from "fs/promises";
import path from "path";
import { Global } from "@opencode-ai/core/global";

const savedDevEcoHomeFile = () => path.join(Global.Path.state, "deveco-home.json");

function binary(name: string) {
  return process.platform === "win32" ? `${name}.exe` : name;
}

function devEcoHomeCandidates(home: string) {
  const normalized = home.trim();
  if (!normalized) {
    return [];
  }
  const candidates = [normalized];
  if (process.platform !== "win32" && path.basename(normalized) !== "Contents") {
    candidates.push(path.join(normalized, "Contents"));
  }
  return candidates;
}

function envPath() {
  return String(process.env.DEVECO_HOME || "").trim();
}

async function isDir(file: string) {
  if (!file) {
    return false;
  }
  return fs
    .stat(file)
    .then((info) => info.isDirectory())
    .catch(() => false);
}

function defaults() {
  if (process.platform === "darwin") {
    return [
      "/Applications/DevEco-Studio.app",
    ];
  }
  if (process.platform === "linux") {
    const home = String(process.env.HOME || "").trim();
    return [
      home ? path.join(home, "devecostudio") : "",
      home ? path.join(home, "DevEco-Studio") : "",
    ].filter(Boolean);
  }
  const home = String(process.env.USERPROFILE || "").trim();
  return [
    "D:\\DevEco Studio",
    "C:\\Program Files\\Huawei\\DevEco Studio",
    "C:\\Program Files\\DevEco Studio",
    "C:\\Program Files (x86)\\DevEco Studio",
    home ? path.join(home, "DevEco Studio") : "",
  ].filter(Boolean);
}

export function nodePath(home: string) {
  return process.platform === "win32"
    ? path.join(home, "tools", "node", "node.exe")
    : path.join(home, "tools", "node", "bin", "node");
}

export function hvigorPath(home: string) {
  return path.join(home, "tools", "hvigor", "bin", "hvigorw.js");
}

export function sdkPath(home: string) {
  return path.join(home, "sdk");
}

export function hdcPath(home: string) {
  return path.join(home, "sdk", "default", "openharmony", "toolchains", binary("hdc"));
}

export async function resolveDevEcoHome(home: string): Promise<string | undefined> {
  for (const candidate of devEcoHomeCandidates(home)) {
    if ((await isDir(candidate)) && (await Bun.file(nodePath(candidate)).exists())) {
      return candidate;
    }
  }
  return undefined;
}

export async function isDevEcoHome(home: string): Promise<boolean> {
  return Boolean(await resolveDevEcoHome(home));
}

export async function findDevEcoHomes(): Promise<string[]> {
  const result: string[] = [];
  const seen = new Set<string>();
  for (const item of defaults()) {
    const home = await resolveDevEcoHome(item);
    if (!home || seen.has(home)) {
      continue;
    }
    seen.add(home);
    result.push(home);
  }
  return result;
}

async function readSavedDevEcoHomeRaw(): Promise<string | undefined> {
  try {
    const text = await fs.readFile(savedDevEcoHomeFile(), "utf8");
    const data = JSON.parse(text) as { deveco_home?: unknown };
    const home = typeof data.deveco_home === "string" ? data.deveco_home.trim() : "";
    return home || undefined;
  } catch {
    return undefined;
  }
}

export async function clearSavedDevEcoHome(): Promise<void> {
  await fs.unlink(savedDevEcoHomeFile()).catch(() => undefined);
}

export async function loadSavedDevEcoHome(): Promise<string | undefined> {
  const raw = await readSavedDevEcoHomeRaw();
  if (!raw) return undefined;
  const resolved = await resolveDevEcoHome(raw);
  if (resolved) return resolved;
  await clearSavedDevEcoHome();
  return undefined;
}

export async function saveDevEcoHome(home: string): Promise<string | undefined> {
  const resolved = await resolveDevEcoHome(home);
  if (!resolved) return undefined;
  await fs.writeFile(savedDevEcoHomeFile(), JSON.stringify({ deveco_home: resolved }, null, 2), "utf8");
  return resolved;
}

export async function findDevEcoHome(): Promise<string | undefined> {
  const env = envPath();
  const home = await resolveDevEcoHome(env);
  if (home) return home;

  const saved = await loadSavedDevEcoHome();
  if (saved) return saved;

  return (await findDevEcoHomes())[0];
}

export function buildEnv(home: string, sdk: string) {
  const sep = process.platform === "win32" ? ";" : ":";
  const raw = process.env.PATH || process.env.Path || process.env.path || "";
  const sys = process.platform === "win32" ? process.env.SystemRoot || process.env.SYSTEMROOT || "C:\\Windows" : "";
  const base = process.platform === "win32" ? path.join(sys, "System32") : "";
  const current = [
    base,
    sys,
    process.platform === "win32" ? path.join(base, "Wbem") : "",
    process.platform === "win32" ? path.join(base, "WindowsPowerShell", "v1.0") : "",
    raw,
  ]
    .filter(Boolean)
    .join(sep);
  const extra = [
    path.join(home, "tools", "node", "bin"),
    path.join(home, "tools", "ohpm", "bin"),
    path.join(home, "tools", "hvigor", "bin"),
  ];
  const merged = [...extra, current].filter(Boolean).join(sep);
  const cmd = process.platform === "win32" ? process.env.ComSpec || process.env.COMSPEC || path.join(base, "cmd.exe") : "";
  return {
    DEVECO_HOME: home,
    DEVECO_SDK_HOME: sdk,
    ...(process.platform === "win32"
      ? {
          SystemRoot: sys,
          SYSTEMROOT: sys,
          ComSpec: cmd,
          COMSPEC: cmd,
          Path: merged,
        }
      : {}),
    PATH: merged,
  };
}