// cell resolve [<locator>] - Print fully resolved dependency closure
//
// Usage:
//   cell resolve           Resolve current directory package
//   cell resolve .         Resolve current directory package
//   cell resolve <locator> Resolve specific package
//
// Options:
//   --target <triple>      Annotate builds for target platform
//   --locked               Show lock state without applying links
//   --refresh              Refresh floating refs before printing

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

var target_locator = null
var target_triple = null
var show_locked = false
var refresh_first = 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] == '--locked') {
    show_locked = true
  } else if (args[i] == '--refresh') {
    refresh_first = true
  } else if (args[i] == '--help' || args[i] == '-h') {
    log.console("Usage: cell resolve [<locator>] [options]")
    log.console("")
    log.console("Print the fully resolved dependency closure.")
    log.console("")
    log.console("Options:")
    log.console("  --target <triple>  Annotate builds for target platform")
    log.console("  --locked           Show lock state without applying links")
    log.console("  --refresh          Refresh floating refs before printing")
    $stop()
  } else if (!starts_with(args[i], '-')) {
    target_locator = args[i]
  }
}

// Default to current directory
if (!target_locator) {
  target_locator = '.'
}

// Resolve local paths
if (target_locator == '.' || starts_with(target_locator, './') || starts_with(target_locator, '../') || fd.is_dir(target_locator)) {
  resolved = fd.realpath(target_locator)
  if (resolved) {
    target_locator = resolved
  }
}

// Check if it's a valid package
var pkg_dir = null
if (!fd.is_file(target_locator + '/cell.toml')) {
  // Try to find it in the shop
  pkg_dir = shop.get_package_dir(target_locator)
  if (!fd.is_file(pkg_dir + '/cell.toml')) {
    log.error("Not a valid package: " + target_locator)
    $stop()
  }
}

// Detect target if not specified
if (!target_triple) {
  target_triple = build.detect_host_target()
}

var lock = shop.load_lock()
var links = link.load()

// Gather all dependencies recursively
var all_deps = {}
var visited = {}

function gather_deps(locator, depth) {
  if (visited[locator]) return
  visited[locator] = true

  all_deps[locator] = { depth: depth }

  var _gather = function() {
    var deps = pkg.dependencies(locator)
    if (deps) {
      arrfor(array(deps), function(alias) {
        var dep_locator = deps[alias]
        gather_deps(dep_locator, depth + 1)
      })
    }
  } disruption {
    // Package might not have dependencies
  }
  _gather()
}

gather_deps(target_locator, 0)

// Print header
log.console("Resolved dependency closure for: " + target_locator)
log.console("Target: " + target_triple)
log.console("")

// Sort by depth then alphabetically
var sorted = array(array(all_deps), function(locator) { return { locator: locator, depth: all_deps[locator].depth } })
sorted = sort(sorted, "locator")
sorted = sort(sorted, "depth")

var j = 0
var locator = null
var depth = 0
var indent = null
var info = null
var lock_entry = null
var link_target = null
var effective_locator = null
var is_linked = false
var is_in_lock = false
var is_local = false
var is_fetched = false
var lib_dir = null
var lib_name = null
var dylib_ext = null
var lib_path = null
var is_built = false
var status_parts = null
var commit_str = null
var line = null
var cflags = null
var ldflags = null
var _show_flags = null

for (i = 0; i < length(sorted); i++) {
  locator = sorted[i].locator
  depth = sorted[i].depth

  indent = ""
  for (j = 0; j < depth; j++) indent += "  "

  // Get info about this package
  info = shop.resolve_package_info(locator)
  lock_entry = lock[locator]
  link_target = show_locked ? null : links[locator]
  effective_locator = link_target || locator

  // Check status
  is_linked = link_target != null
  is_in_lock = lock_entry != null
  is_local = info == 'local'

  // Check if fetched (package directory exists)
  pkg_dir = shop.get_package_dir(locator)
  is_fetched = fd.is_dir(pkg_dir) || fd.is_link(pkg_dir)

  // Check if built (library exists)
  lib_dir = shop.get_lib_dir()
  lib_name = shop.lib_name_for_package(locator)
  dylib_ext = '.dylib' // TODO: detect from target
  lib_path = lib_dir + '/' + lib_name + dylib_ext
  is_built = fd.is_file(lib_path)

  // Format output
  status_parts = []
  if (is_linked) push(status_parts, "linked")
  if (is_local) push(status_parts, "local")
  if (!is_in_lock) push(status_parts, "not in lock")
  if (!is_fetched) push(status_parts, "not fetched")
  if (is_built) push(status_parts, "built")

  commit_str = ""
  if (lock_entry && lock_entry.commit) {
    commit_str = " @" + text(lock_entry.commit, 0, 8)
  } else if (lock_entry && lock_entry.type == 'local') {
    commit_str = " (local)"
  }

  line = indent + locator + commit_str

  if (is_linked && !show_locked) {
    line += " -> " + link_target
  }

  if (length(status_parts) > 0) {
    line += " [" + text(status_parts, ", ") + "]"
  }

  log.console(line)

  // Show compilation inputs if requested (verbose)
  if (depth == 0) {
    _show_flags = function() {
      cflags = pkg.get_flags(locator, 'CFLAGS', target_triple)
      ldflags = pkg.get_flags(locator, 'LDFLAGS', target_triple)
      if (length(cflags) > 0 || length(ldflags) > 0) {
        log.console(indent + "  Compilation inputs:")
        if (length(cflags) > 0) {
          log.console(indent + "    CFLAGS: " + text(cflags, ' '))
        }
        if (length(ldflags) > 0) {
          log.console(indent + "    LDFLAGS: " + text(ldflags, ' '))
        }
      }
    } disruption {
      // Skip if can't read config
    }
    _show_flags()
  }
}

log.console("")
log.console("Total: " + text(length(sorted)) + " package(s)")

$stop()
