// Link management module for cell packages
// Handles creating, removing, and syncing symlinks for local development

var toml = use('toml')
var fd = use('fd')
var blob = use('blob')
var runtime = use('runtime')

var global_shop_path = runtime.shop_path

// Get the links file path (in the global shop)
function get_links_path() {
  if (!global_shop_path) return null
  return global_shop_path + '/link.toml'
}

// Get the packages directory (in the global shop)
function get_packages_dir() {
  if (!global_shop_path) return null
  return global_shop_path + '/packages'
}

function get_package_abs_dir(package) {
  return get_packages_dir() + '/' + fd.safe_package_path(package)
}

// Resolve a link target to its actual path
// If target is a local path (starts with /), return it directly
// If target is a package name, return the package directory
function resolve_link_target(target) {
  if (starts_with(target, '/')) {
    return target
  }
  // Target is another package - resolve to its directory
  return get_packages_dir() + '/' + fd.safe_package_path(target)
}

var Link = {}

var link_cache = null

Link.load = function() {
  if (link_cache) return link_cache
  var path = get_links_path()
  if (!path || !fd.is_file(path)) {
    link_cache = {}
    return link_cache
  }
  
  var _load = function() {
    var content = text(fd.slurp(path))
    var cfg = toml.decode(content)
    if (cfg && cfg.links) link_cache = cfg.links
    else link_cache = {}
  } disruption {
    log.build("Warning: Failed to load link.toml")
    link_cache = {}
  }
  _load()
  return link_cache
}

Link.save = function(links) {
  link_cache = links
  var cfg = { links: links }
  var path = get_links_path()
  var b = blob(toml.encode(cfg))
  stone(b)
  fd.slurpwrite(path, b)
}

Link.add = function(canonical, target, shop) {
  // Validate canonical package exists in shop
  var lock = shop.load_lock()
  if (!lock[canonical]) {
    log.error('Package ' + canonical + ' is not installed. Install it first with: cell get ' + canonical)
    disrupt
  }

  // Validate target is a valid package
  if (starts_with(target, '/')) {
    // Local path - must have cell.toml
    if (!fd.is_file(target + '/cell.toml')) {
      log.error('Target ' + target + ' is not a valid package (no cell.toml)')
      disrupt
    }
  } else {
    // Remote package target - ensure it's installed
    shop.sync(target)
  }

  var links = Link.load()
  links[canonical] = target
  Link.save(links)

  // Create the symlink immediately
  Link.sync_one(canonical, target, shop)

  // Install dependencies of the linked package
  // Read the target's cell.toml to find its dependencies
  var target_path = starts_with(target, '/') ? target : get_package_abs_dir(target)
  var toml_path = target_path + '/cell.toml'
  var _install_deps = null
  if (fd.is_file(toml_path)) {
    _install_deps = function() {
      var content = text(fd.slurp(toml_path))
      var cfg = toml.decode(content)
      if (cfg && cfg.dependencies) {
        arrfor(array(cfg.dependencies), function(alias) {
          var dep_locator = cfg.dependencies[alias]
          // Skip local dependencies that don't exist
          if (starts_with(dep_locator, '/') && !fd.is_dir(dep_locator)) {
            log.build("  Skipping missing local dependency: " + dep_locator)
            return
          }
          // Install the dependency if not already in shop
          var _get_dep = function() {
            shop.sync(dep_locator)
          } disruption {
            log.build(`  Warning: Could not install dependency ${dep_locator}`)
          }
          _get_dep()
        })
      }
    } disruption {
      log.build(`  Warning: Could not read dependencies from ${toml_path}`)
    }
    _install_deps()
  }

  log.build("Linked " + canonical + " -> " + target)
  return true
}

Link.remove = function(canonical) {
  var links = Link.load()
  if (!links[canonical]) return false
  
  // Remove the symlink if it exists
  var target_dir = get_package_abs_dir(canonical)
  if (fd.is_link(target_dir)) {
    fd.unlink(target_dir)
    log.build("Removed symlink at " + target_dir)
  }

  delete links[canonical]
  Link.save(links)
  log.build("Unlinked " + canonical)
  return true
}

Link.clear = function() {
  // Remove all symlinks first
  var links = Link.load()
  arrfor(array(links), function(canonical) {
    var target_dir = get_package_abs_dir(canonical)
    if (fd.is_link(target_dir)) {
      fd.unlink(target_dir)
    }
  })
  
  Link.save({})
  log.build("Cleared all links")
  return true
}

// Sync a single link - ensure the symlink is in place
Link.sync_one = function(canonical, target, shop) {
  var target_dir = get_package_abs_dir(canonical)
  var link_target = resolve_link_target(target)

  // Ensure parent directories exist
  var parent = fd.dirname(target_dir)
  fd.ensure_dir(parent)
  
  // Check current state
  var current_link = null
  if (fd.is_link(target_dir)) {
    current_link = fd.readlink(target_dir)
  }
  
  // If already correctly linked, nothing to do
  if (current_link == link_target) {
    return true
  }
  
  // Remove existing file/dir/link
  if (fd.is_link(target_dir)) {
    fd.unlink(target_dir)
  } else if (fd.is_dir(target_dir)) {
    fd.rmdir(target_dir, 1)
  }
  
  // Create symlink
  fd.symlink(link_target, target_dir)
  return true
}

// Sync all links - ensure all symlinks are in place and dependencies are installed
Link.sync_all = function(shop) {
  var links = Link.load()
  var count = 0
  var errors = []

  arrfor(array(links), function(canonical) {
    var target = links[canonical]
    var _sync = function() {
      // Validate target exists
      var link_target = resolve_link_target(target)
      if (!fd.is_dir(link_target)) {
        push(errors, canonical + ': target ' + link_target + ' does not exist')
        return
      }
      if (!fd.is_file(link_target + '/cell.toml')) {
        push(errors, canonical + ': target ' + link_target + ' is not a valid package')
        return
      }

      Link.sync_one(canonical, target, shop)

      // Install dependencies of the linked package
      var toml_path = link_target + '/cell.toml'
      var _install = function() {
        var content = text(fd.slurp(toml_path))
        var cfg = toml.decode(content)
        if (cfg && cfg.dependencies) {
          arrfor(array(cfg.dependencies), function(alias) {
            var dep_locator = cfg.dependencies[alias]
            // Skip local dependencies that don't exist
            if (starts_with(dep_locator, '/') && !fd.is_dir(dep_locator)) {
              return
            }
            // Install the dependency if not already in shop
            var _get = function() {
              shop.sync(dep_locator)
            } disruption {
              // Silently continue - dependency may already be installed
            }
            _get()
          })
        }
      } disruption {
        // Could not read dependencies - continue anyway
      }
      _install()

      count = count + 1
    } disruption {
      push(errors, canonical + ': sync failed')
    }
    _sync()
  })

  return { synced: count, errors: errors }
}

// Check if a package is currently linked
Link.is_linked = function(canonical) {
  var links = Link.load()
  return links[canonical] != null
}

// Get the link target for a package (or null if not linked)
Link.get_target = function(canonical) {
  var links = Link.load()
  return links[canonical] || null
}

// Get the canonical package name that links to this target (reverse lookup)
// Returns null if no package links to this target
Link.get_origin = function(target) {
  var links = Link.load()
  var found = null
  arrfor(array(links), function(origin) {
    if (links[origin] == target) found = origin
  })
  return found
}

return Link
