// cell why - Show reverse dependencies for a package

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

if (!args || length(args) < 1) {
    log.console("Usage: cell why <package>")
    $stop()
}

var target = args[0]
log.console("Searching for '" + target + "'...")

var target_clean = target
if (starts_with(target_clean, '/')) target_clean = text(target_clean, 1)

var found = false

// DFS to find paths
// current_pkg: canonical path of current package (null for root)
// stack: array of {alias, pkg} leading to current_pkg

function search_deps(current_pkg, stack) {
    var deps = pkg.dependencies(current_pkg)
    var aliases = sort(array(deps))
    var i = 0
    var alias = null
    var locator = null
    var parsed = null
    var canon = null
    var locator_clean = null
    var match = false
    var node = null
    var new_stack = null
    var cycle = false
    var j = 0

    for (i = 0; i < length(aliases); i++) {
        alias = aliases[i]
        locator = deps[alias]
        parsed = shop.parse_package(locator)
        if (!parsed) continue

        canon = parsed.path

        locator_clean = locator
        if (search(locator, '@') != null) locator_clean = array(locator, '@')[0]

        // Check if match
        // 1. Alias matches
        // 2. Package name matches
        // 3. Canonical path matches (exact or clean)
        // 4. Locator matches (exact or clean)
        match = (alias == target) ||
                    (parsed.name == target) ||
                    (canon == target) ||
                    (canon == target_clean) ||
                    (locator == target) ||
                    (locator_clean == target)

        node = { alias: alias, pkg: canon, locator: locator }
        new_stack = stack.concat([node])

        if (match) {
            found = true
            print_stack(new_stack)
            // Don't recurse if we found the target in this branch
            continue
        }

        // Recurse if not seen in current stack (cycle detection)
        cycle = false
        for (j = 0; j < length(stack); j++) {
            if (stack[j].pkg == canon) {
                cycle = true
                break
            }
        }

        if (!cycle) {
            search_deps(canon, new_stack)
        }
    }
}

function print_stack(stack) {
    // Calculate max width for alignment if needed, but simple tree is fine
    var output = "project"
    var i = 0
    var node = null
    var indent = null
    var j = 0
    var info = null
    log.console(output)

    for (i = 0; i < length(stack); i++) {
        node = stack[i]
        indent = ""
        for (j = 0; j <= i; j++) indent += "  "

        info = node.locator
        if (node.alias != parsed_name(node.locator)) {
             // info += " (aliased as " + node.alias + ")"
        }

        log.console(indent + "-> " + node.alias + " (" + info + ")")
    }
    log.console("")
}

function parsed_name(locator) {
    var parsed = shop.parse_package(locator)
    return parsed ? parsed.name : ""
}

search_deps(null, [])

if (!found) {
    log.console("Package '" + target + "' not found in dependency tree.")
}

$stop()
