// cell config - Manage system and actor configurations

var toml = use('toml')
var pkg = use('package')

function print_help() {
  log.console("Usage: cell config <command> [options]")
  log.console("")
  log.console("Commands:")
  log.console("  get <key>                    Get a configuration value")
  log.console("  set <key> <value>            Set a configuration value")
  log.console("  list                         List all configurations")
  log.console("  actor <name> get <key>       Get actor-specific config")
  log.console("  actor <name> set <key> <val> Set actor-specific config")
  log.console("  actor <name> list            List actor configurations")
  log.console("")
  log.console("Examples:")
  log.console("  cell config get system.ar_timer")
  log.console("  cell config set system.net_service 0.2")
  log.console("  cell config actor prosperon/_sdl_video set resolution 1920x1080")
  log.console("  cell config actor extramath/spline set precision high")
  log.console("")
  log.console("System keys:")
  log.console("  system.ar_timer         - Seconds before idle actor reclamation")
  log.console("  system.actor_memory     - MB of memory an actor can use (0=unbounded)")
  log.console("  system.net_service      - Seconds per network service pull")
  log.console("  system.reply_timeout    - Seconds to hold callback for replies (0=unbounded)")
  log.console("  system.actor_max        - Max number of simultaneous actors")
  log.console("  system.stack_max        - MB of memory each actor's stack can grow to")
}

// Parse a dot-notation key into path segments
function parse_key(key) {
  return array(key, '.')
}

// Get a value from nested object using path
function get_nested(obj, path) {
  var current = obj
  arrfor(path, function(segment) {
    if (is_null(current) || !is_object(current)) return null
    current = current[segment]
  })
  return current
}

// Set a value in nested object using path
function set_nested(obj, path, value) {
  var current = obj
  var i = 0
  var segment = null
  for (i = 0; i < length(path) - 1; i++) {
    segment = path[i]
    if (is_null(current[segment]) || !is_object(current[segment])) {
      current[segment] = {}
    }
    current = current[segment]
  }
  current[path[length(path) - 1]] = value
}

// Parse value string into appropriate type
function parse_value(str) {
  var num_str = null
  var n = null
  // Boolean
  if (str == 'true') return true
  if (str == 'false') return false

  // Number
  num_str = replace(str, /_/g, '')
  n = number(num_str)
  if (n != null) return n

  // String
  return str
}

// Format value for display
function format_value(val) {
  if (is_text(val)) return '"' + val + '"'
  return text(val)
}

// Print configuration tree recursively
function print_config(obj, pfx) {
  var p = pfx || ''
  arrfor(array(obj), function(key) {
    var val = obj[key]
    var full_key = p ? p + '.' + key : key

    if (is_object(val))
      print_config(val, full_key)
    else if (!is_null(val))
      log.console(full_key + ' = ' + format_value(val))
  })
}

// Main command handling
if (length(args) == 0) {
  print_help()
  $stop()
}

var config = pkg.load_config()
if (!config) {
  log.error("Failed to load cell.toml")
  $stop()
}

var command = args[0]
var key = null
var path = null
var value = null
var value_str = null
var valid_system_keys = null
var actor_name = null
var actor_cmd = null

if (command == 'help' || command == '-h' || command == '--help') {
  print_help()
} else if (command == 'list') {
  log.console("# Cell Configuration")
  log.console("")
  print_config(config)
} else if (command == 'get') {
  if (length(args) < 2) {
    log.error("Usage: cell config get <key>")
    $stop()
  }
  key = args[1]
  path = parse_key(key)
  value = get_nested(config, path)

  if (value == null) {
    log.error("Key not found: " + key)
  } else if (is_object(value)) {
    print_config(value, key)
  } else {
    log.console(key + ' = ' + format_value(value))
  }
} else if (command == 'set') {
  if (length(args) < 3) {
    log.error("Usage: cell config set <key> <value>")
    $stop()
  }
  key = args[1]
  value_str = args[2]
  path = parse_key(key)
  value = parse_value(value_str)

  if (path[0] == 'system') {
    valid_system_keys = [
      'ar_timer', 'actor_memory', 'net_service',
      'reply_timeout', 'actor_max', 'stack_max'
    ]
    if (find(valid_system_keys, path[1]) == null) {
      log.error("Invalid system key. Valid keys: " + text(valid_system_keys, ', '))
      $stop()
    }
  }

  set_nested(config, path, value)
  pkg.save_config(config)
  log.console("Set " + key + " = " + format_value(value))
} else if (command == 'actor') {
  if (length(args) < 3) {
    log.error("Usage: cell config actor <name> <command> [options]")
    $stop()
  }

  actor_name = args[1]
  actor_cmd = args[2]

  config.actors = config.actors || {}
  config.actors[actor_name] = config.actors[actor_name] || {}

  if (actor_cmd == 'list') {
    if (length(array(config.actors[actor_name])) == 0) {
      log.console("No configuration for actor: " + actor_name)
    } else {
      log.console("# Configuration for actor: " + actor_name)
      log.console("")
      print_config(config.actors[actor_name], 'actors.' + actor_name)
    }
  } else if (actor_cmd == 'get') {
    if (length(args) < 4) {
      log.error("Usage: cell config actor <name> get <key>")
      $stop()
    }
    key = args[3]
    path = parse_key(key)
    value = get_nested(config.actors[actor_name], path)

    if (value == null) {
      log.error("Key not found for actor " + actor_name + ": " + key)
    } else {
      log.console('actors.' + actor_name + '.' + key + ' = ' + format_value(value))
    }
  } else if (actor_cmd == 'set') {
    if (length(args) < 5) {
      log.error("Usage: cell config actor <name> set <key> <value>")
      $stop()
    }
    key = args[3]
    value_str = args[4]
    path = parse_key(key)
    value = parse_value(value_str)

    set_nested(config.actors[actor_name], path, value)
    pkg.save_config(config)
    log.console("Set actors." + actor_name + "." + key + " = " + format_value(value))
  } else {
    log.error("Unknown actor command: " + actor_cmd)
    log.console("Valid commands: list, get, set")
  }
} else {
  log.error("Unknown command: " + command)
  print_help()
}

$stop()
