import fs from "node:fs/promises";
import path from "node:path";
import process from "node:process";

import { detectProjectRoot } from "../project/detect-project-root.js";
import { invokePowerShellScript } from "../powershell/invoke-script.js";
import {
  getDownloadedManifestPath,
  getDownloadedShaPath,
  getDownloadedZipPath,
  getPackageInstallRoot,
  getReleaseAssetNames,
  getUserPackageLockPath
} from "../release/cache-layout.js";
import { downloadToFile, fileExists } from "../release/download-release.js";
import { buildReleaseAssetUrl } from "../release/release-config.js";
import { getReleasePlatformEntry } from "../release/release-manifest.js";
import { resolvePackageSourceRoot } from "../release/resolve-package-source.js";
import { resolveVersion } from "../release/resolve-version.js";
import { unpackZip } from "../release/unpack-zip.js";
import { verifyFileSha256 } from "../release/verify-sha256.js";

function getLocalPackageRoot() {
  return path.resolve(import.meta.dirname, "..", "..", "..");
}

function getCliPackageRoot() {
  return path.resolve(import.meta.dirname, "..", "..");
}

async function readManifestVersion(packageRoot) {
  const manifestPath = path.join(packageRoot, "install-manifest.json");
  const manifestDocument = JSON.parse(await fs.readFile(manifestPath, "utf8"));
  const version = typeof manifestDocument.version === "string" ? manifestDocument.version.trim() : "";
  if (version === "") {
    throw new Error(`install-manifest.json 缺少 version: ${manifestPath}`);
  }

  return version;
}

async function readInstalledUserCacheVersion(userProfile) {
  const lockPath = getUserPackageLockPath(userProfile);
  if (!fileExists(lockPath)) {
    return "";
  }

  try {
    const lockDocument = JSON.parse(await fs.readFile(lockPath, "utf8"));
    return typeof lockDocument.version === "string" ? lockDocument.version.trim() : "";
  } catch {
    return "";
  }
}

export function shouldRefreshUserPackageCache(expectedVersion, installedVersion, installRootExists) {
  if (!installRootExists) {
    return true;
  }

  return expectedVersion !== installedVersion;
}

export function shouldBypassBundledPackageSource(requestedVersion, bundledVersion) {
  if (!requestedVersion || requestedVersion === "latest") {
    return false;
  }

  return requestedVersion !== bundledVersion;
}

async function ensureUserPackageCache(options) {
  const expectedVersion = await readManifestVersion(options.packageRoot);
  const installedVersion = await readInstalledUserCacheVersion(options.userProfile);
  const expectedInstallRoot = getPackageInstallRoot(options.userProfile, expectedVersion);

  if (!shouldRefreshUserPackageCache(expectedVersion, installedVersion, fileExists(expectedInstallRoot))) {
    return;
  }

  const scriptPath = path.join(options.packageRoot, "tools", "install", "install-user.ps1");
  process.stdout.write(`刷新用户级 codex-harness 缓存到 ${expectedVersion}...\n`);
  const args = [];
  if (options.force) {
    args.push("-Force");
  }
  await invokePowerShellScript(scriptPath, args, { cwd: options.packageRoot });
}

export async function initCommand(options) {
  const localPackageRoot = getLocalPackageRoot();
  const embeddedPackageRoot = path.join(getCliPackageRoot(), "package-source");
  const projectRoot = detectProjectRoot(options.projectRoot);
  const userProfile = process.env.USERPROFILE;
  if (!userProfile) {
    throw new Error("USERPROFILE is not set.");
  }

  const requestedVersion = options.version ? await resolveVersion(options.version) : "";
  let packageRoot = resolvePackageSourceRoot({
    packageRoot: localPackageRoot,
    embeddedRoot: embeddedPackageRoot,
    cachedRoot: "",
    fsLike: { existsSync: fileExists }
  });

  if (packageRoot !== "" && requestedVersion) {
    const bundledVersion = await readManifestVersion(packageRoot);
    if (shouldBypassBundledPackageSource(requestedVersion, bundledVersion)) {
      packageRoot = "";
    }
  }

  let effectivePackageRoot = packageRoot;
  if (effectivePackageRoot === "") {
    const version = requestedVersion || (await resolveVersion(options.version));
    const manifestPath = getDownloadedManifestPath(userProfile, version);
    const fallbackAssets = getReleaseAssetNames(version);

    if (!fileExists(manifestPath)) {
      await downloadToFile(buildReleaseAssetUrl({ version, assetName: fallbackAssets.manifest }), manifestPath);
    }

    const releaseManifest = JSON.parse(await fs.readFile(manifestPath, "utf8"));
    const releaseAssets = getReleasePlatformEntry(releaseManifest);
    if (releaseAssets.version !== version) {
      throw new Error(`Release manifest version mismatch: expected ${version}, got ${releaseAssets.version}`);
    }

    const packageInstallRoot = getPackageInstallRoot(userProfile, releaseAssets.version);
    const zipPath = getDownloadedZipPath(userProfile, releaseAssets.version);
    const shaPath = getDownloadedShaPath(userProfile, releaseAssets.version);

    if (!fileExists(zipPath)) {
      await downloadToFile(buildReleaseAssetUrl({ version, assetName: releaseAssets.zip }), zipPath);
    }

    if (!fileExists(shaPath)) {
      await downloadToFile(buildReleaseAssetUrl({ version, assetName: releaseAssets.sha256File }), shaPath);
    }

    await verifyFileSha256(zipPath, shaPath, releaseAssets.sha256);

    if (!fileExists(path.join(packageInstallRoot, "tools", "install", "install-agent.ps1"))) {
      await unpackZip(zipPath, packageInstallRoot);
    }

    effectivePackageRoot = packageInstallRoot;
  }

  if (!options.plan) {
    await ensureUserPackageCache({
      packageRoot: effectivePackageRoot,
      userProfile,
      force: options.force
    });
  }

  const scriptPath = path.join(effectivePackageRoot, "tools", "install", "install-agent.ps1");
  const args = ["-ProjectRoot", projectRoot];

  if (options.vendor) {
    args.push("-Scope", "vendor");
  } else {
    args.push("-Scope", "project");
  }

  if (options.force) {
    args.push("-Force");
  }

  if (options.initGit !== false) {
    args.push("-InitGitIfNeeded");
  }

  if (options.plan) {
    args.push("-Plan");
  }

  await invokePowerShellScript(scriptPath, args, { cwd: effectivePackageRoot });
}
