// cell imports [<file>] - Trace module-level imports
//
// Usage:
//   cell imports                 Trace imports for current package entry
//   cell imports <file.ce>       Trace imports starting from a .ce or .cm file
//   cell imports <file.cm>       Trace imports starting from a .cm file
//
// Options:
//   --flat       Flat list instead of tree
//   --packages   Only show unique packages, not individual modules

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

var target = null
var flat_mode = false
var packages_only = false
var i = 0
var pkg_dir = null
var config = null
var target_path = null

for (i = 0; i < length(args); i++) {
  if (args[i] == '--flat') {
    flat_mode = true
  } else if (args[i] == '--packages') {
    packages_only = true
  } else if (args[i] == '--help' || args[i] == '-h') {
    log.console("Usage: cell imports [<file>] [options]")
    log.console("")
    log.console("Trace module-level imports across packages.")
    log.console("")
    log.console("Options:")
    log.console("  --flat       Flat list instead of tree")
    log.console("  --packages   Only show unique packages, not individual modules")
    $stop()
  } else if (!starts_with(args[i], '-')) {
    target = args[i]
  }
}

// Resolve target file
if (target) {
  if (!ends_with(target, '.ce') && !ends_with(target, '.cm'))
    target = target + '.ce'
  if (fd.is_file(target))
    target_path = fd.realpath(target)
  else {
    pkg_dir = pkg.find_package_dir('.')
    if (pkg_dir)
      target_path = pkg_dir + '/' + target
  }
} else {
  pkg_dir = pkg.find_package_dir('.')
  if (pkg_dir) {
    config = pkg.load_config(null)
    if (config.entry)
      target_path = pkg_dir + '/' + config.entry
  }
}

if (!target_path || !fd.is_file(target_path)) {
  log.error('Could not find file: ' + (target || '(no target specified)'))
  $stop()
}

// Collect all imports recursively
var visited = {}
var all_imports = []
var all_packages = {}

function trace_imports(file_path, depth) {
  if (visited[file_path]) return
  visited[file_path] = true

  var fi = shop.file_info(file_path)
  var file_pkg = fi.package || '(local)'
  var idx = null
  var j = 0
  var imp = null
  var mod_path = null
  var resolved = null
  var imp_pkg = null
  var imp_type = null
  var rinfo = null

  all_packages[file_pkg] = true

  var _trace = function() {
    idx = shop.index_file(file_path)
    if (!idx || !idx.imports) return

    j = 0
    while (j < length(idx.imports)) {
      imp = idx.imports[j]
      mod_path = imp.module_path
      resolved = null
      imp_pkg = '?'
      imp_type = 'unresolved'

      // Use the full resolver that checks .cm files, C symbols, and aliases
      rinfo = shop.resolve_import_info(mod_path, file_pkg)
      if (rinfo) {
        resolved = rinfo.resolved_path
        imp_pkg = rinfo.package || '?'
        imp_type = rinfo.type
      }

      all_packages[imp_pkg] = true

      push(all_imports, {
        from: file_path,
        from_pkg: file_pkg,
        module_path: mod_path,
        resolved_path: resolved,
        package: imp_pkg,
        type: imp_type,
        depth: depth
      })

      // Recurse into resolved scripts
      if (resolved && (ends_with(resolved, '.cm') || ends_with(resolved, '.ce'))) {
        trace_imports(resolved, depth + 1)
      }
      j = j + 1
    }
  } disruption {
    // File might fail to parse/index
  }
  _trace()
}

trace_imports(target_path, 0)

// Output results
var fi2 = null
if (packages_only) {
  log.console("Packages used by " + target_path + ":")
  log.console("")
  arrfor(array(all_packages), function(p) {
    log.console("  " + p)
  })
} else if (flat_mode) {
  log.console("Imports from " + target_path + ":")
  log.console("")
  arrfor(all_imports, function(imp) {
    var suffix = ''
    if (imp.type == 'native') suffix = ' [native]'
    if (imp.type == 'unresolved') suffix = ' [unresolved]'
    log.console("  " + imp.module_path + " -> " + imp.package + suffix)
  })
} else {
  // Tree output
  function print_tree(file_path, prefix, is_last) {
    var children = filter(all_imports, function(imp) {
      return imp.from == file_path
    })

    var j = 0
    var imp = null
    var last = false
    var connector = null
    var suffix = null
    var child_prefix = null
    while (j < length(children)) {
      imp = children[j]
      last = (j == length(children) - 1)
      connector = last ? "\\-- " : "|-- "
      suffix = " (" + imp.package + ")"
      if (imp.type == 'native') suffix = suffix + " [native]"
      if (imp.type == 'unresolved') suffix = suffix + " [unresolved]"

      log.console(prefix + connector + imp.module_path + suffix)

      if (imp.resolved_path) {
        child_prefix = prefix + (last ? "    " : "|   ")
        print_tree(imp.resolved_path, child_prefix, last)
      }
      j = j + 1
    }
  }

  fi2 = shop.file_info(target_path)
  log.console(target_path + " (" + (fi2.package || 'local') + ")")
  print_tree(target_path, "", true)
}

$stop()
