// cell install <locator> - Install a package to the shop
//
// Usage:
//   cell install <locator>   Install a package and its dependencies
//   cell install .           Install current directory package
//
// Options:
//   --target <triple>   Build for target platform
//   --refresh           Refresh floating refs before locking
//   --dry-run           Show what would be installed

var shop = use('internal/shop')
var build = use('build')
var pkg = use('package')
var fd = use('fd')

if (length(args) < 1) {
  log.console("Usage: cell install <locator> [options]")
  log.console("")
  log.console("Options:")
  log.console("  --target <triple>  Build for target platform")
  log.console("  --refresh          Refresh floating refs before locking")
  log.console("  --dry-run          Show what would be installed")
  $stop()
}

var locator = null
var target_triple = null
var refresh = false
var dry_run = false
var i = 0
var resolved = null

for (i = 0; i < length(args); i++) {
  if (args[i] == '--target' || args[i] == '-t') {
    if (i + 1 < length(args)) {
      target_triple = args[++i]
    } else {
      log.error('--target requires a triple')
      $stop()
    }
  } else if (args[i] == '--refresh') {
    refresh = true
  } else if (args[i] == '--dry-run') {
    dry_run = true
  } else if (args[i] == '--help' || args[i] == '-h') {
    log.console("Usage: cell install <locator> [options]")
    log.console("")
    log.console("Install a package and its dependencies to the shop.")
    log.console("")
    log.console("Options:")
    log.console("  --target <triple>  Build for target platform")
    log.console("  --refresh          Refresh floating refs before locking")
    log.console("  --dry-run          Show what would be installed")
    $stop()
  } else if (!starts_with(args[i], '-')) {
    locator = args[i]
  }
}

if (!locator) {
  log.console("Usage: cell install <locator>")
  $stop()
}

// Resolve relative paths to absolute paths
// Local paths like '.' or '../foo' need to be converted to absolute paths
if (locator == '.' || starts_with(locator, './') || starts_with(locator, '../') || fd.is_dir(locator)) {
  resolved = fd.realpath(locator)
  if (resolved) {
    locator = resolved
  }
}

// Default target
if (!target_triple) {
  target_triple = build.detect_host_target()
}

log.console("Installing " + locator + "...")

// Gather all packages that will be installed
var packages_to_install = []
var skipped_packages = []
var visited = {}

function gather_packages(pkg_locator) {
  var lock = null
  var update_result = null
  var deps = null
  if (visited[pkg_locator]) return
  visited[pkg_locator] = true

  // Check if this is a local path that doesn't exist
  if (starts_with(pkg_locator, '/') && !fd.is_dir(pkg_locator)) {
    push(skipped_packages, pkg_locator)
    log.console("  Skipping missing local package: " + pkg_locator)
    return
  }

  push(packages_to_install, pkg_locator)

  // Try to read dependencies
  var _gather = function() {
    // For packages not yet extracted, we need to update and extract first to read deps
    lock = shop.load_lock()
    if (!lock[pkg_locator]) {
      if (!dry_run) {
        update_result = shop.update(pkg_locator)
        if (update_result) {
          shop.extract(pkg_locator)
        } else {
          // Update failed - package might not be fetchable
          log.console("Warning: Could not fetch " + pkg_locator)
          return
        }
      }
    } else {
      // Package is in lock, ensure it's extracted
      if (!dry_run) {
        shop.extract(pkg_locator)
      }
    }

    deps = pkg.dependencies(pkg_locator)
    if (deps) {
      arrfor(array(deps), function(alias) {
        var dep_locator = deps[alias]
        gather_packages(dep_locator)
      })
    }
  } disruption {
    // Package might not have dependencies or cell.toml issue
    if (!dry_run) {
      log.console(`Warning: Could not read dependencies for ${pkg_locator}`)
    }
  }
  _gather()
}

// Gather all packages
gather_packages(locator)

if (dry_run) {
  log.console("Would install:")
  arrfor(packages_to_install, function(p) {
    var lock = shop.load_lock()
    var exists = lock[p] != null
    log.console("  " + p + (exists ? " (already installed)" : ""))
  })
  if (length(skipped_packages) > 0) {
    log.console("")
    log.console("Would skip (missing local paths):")
    arrfor(skipped_packages, function(p) {
      log.console("  " + p)
    })
  }
  $stop()
}

// Install each package
function install_package(pkg_locator) {
  // Update lock entry
  shop.update(pkg_locator)

  // Extract/symlink the package
  shop.extract(pkg_locator)

  // Build scripts
  shop.build_package_scripts(pkg_locator)

  // Build C code
  var _build_c = function() {
    build.build_dynamic(pkg_locator, target_triple, 'release')
  } disruption {
    // Not all packages have C code
  }
  _build_c()
}

arrfor(packages_to_install, function(p) {
  log.console("  Installing " + p + "...")
  install_package(p)
})

var summary = "Installed " + text(length(packages_to_install)) + " package(s)."
if (length(skipped_packages) > 0) {
  summary += " Skipped " + text(length(skipped_packages)) + " missing local path(s)."
}
log.console(summary)

$stop()
