// Bindings - Action map, rebinding, and icon lookup
var io = use('cellfs')
var json = use('json')

// Controller icon map
var controller_map = {
  ps3: 'playstation',
  ps4: 'playstation',
  ps5: 'playstation',
  xbox360: 'xbox360',
  xboxone: 'xboxone',
  standard: 'standard',
  gamecube: 'gamecube',
  switchpro: 'switchpro',
  joyconleft: 'joyconleft',
  joyconright: 'joyconright',
  joyconpair: 'joyconpair'
}

function make(defaults, display_names) {
  defaults = defaults || {}
  display_names = display_names || {}
  
  var bindings = {
    action_map: {},
    _defaults: {},
    display_names: display_names,
    is_rebinding: false,
    rebind_target: null
  }
  
  // Copy defaults
  arrfor(array(defaults), function(key){
    var val = defaults[key]
    bindings.action_map[key] = is_array(val) ? array(val) : [val]
    bindings._defaults[key] = array(bindings.action_map[key])
  })
  
  // Get actions that match a control
  bindings.get_actions = function(control) {
    return filter(array(this.action_map), action => find(this.action_map[action], control) != null)
  }
  
  // Get bindings for a specific device kind
  bindings.get_bindings_for_device = function(action, device_kind) {
    var all = this.action_map[action] || []
    return filter(all, control => {
      if (device_kind == 'keyboard') {
        return !starts_with(control, 'gamepad_') && !starts_with(control, 'swipe_') && !starts_with(control, 'touch')
      }
      if (device_kind == 'gamepad') {
        return starts_with(control, 'gamepad_')
      }
      if (device_kind == 'touch') {
        return starts_with(control, 'swipe_') || starts_with(control, 'touch')
      }
      return true
    })
  }
  
  // Get primary binding for display
  bindings.get_primary_binding = function(action, device_kind) {
    var device_bindings = this.get_bindings_for_device(action, device_kind)
    if (length(device_bindings)) return device_bindings[0]
    
    var all = this.action_map[action] || []
    return length(all) > 0 ? all[0] : null
  }
  
  // Get icon for action
  bindings.get_icon_for_action = function(action, device_kind, gamepad_type) {
    var binding = this.get_primary_binding(action, device_kind)
    if (!binding) return null
    
    if (device_kind == 'keyboard') {
      if (starts_with(binding, 'mouse_button_')) {
        var button = replace(binding, 'mouse_button_', '')
        return 'ui/mouse/mouse_' + button + '.png'
      } else {
        var key_map = {
          'escape': 'escape', 'return': 'return', 'space': 'space',
          'up': 'arrow_up', 'down': 'arrow_down', 'left': 'arrow_left', 'right': 'arrow_right'
        }
        var key = key_map[binding] || binding
        return 'ui/keyboard/keyboard_' + key + '.png'
      }
    }
    
    if (device_kind == 'gamepad' && gamepad_type) {
      var prefix = controller_map[gamepad_type] || 'playstation'
      var is_ps = find(['ps3', 'ps4', 'ps5'], gamepad_type) != null
      
      var gamepad_map = {
        'gamepad_a': is_ps ? 'playstation_button_cross' : 'xbox_button_a',
        'gamepad_b': is_ps ? 'playstation_button_circle' : 'xbox_button_b',
        'gamepad_x': is_ps ? 'playstation_button_square' : 'xbox_button_x',
        'gamepad_y': is_ps ? 'playstation_button_triangle' : 'xbox_button_y',
        'gamepad_dpup': prefix + '_dpad_up',
        'gamepad_dpdown': prefix + '_dpad_down',
        'gamepad_dpleft': prefix + '_dpad_left',
        'gamepad_dpright': prefix + '_dpad_right',
        'gamepad_l1': prefix + '_trigger_l1',
        'gamepad_r1': prefix + '_trigger_r1',
        'gamepad_l2': prefix + '_trigger_l2',
        'gamepad_r2': prefix + '_trigger_r2',
        'gamepad_start': this._get_start_icon(gamepad_type)
      }
      
      var icon = gamepad_map[binding]
      if (icon) return 'ui/' + prefix + '/' + icon + '.png'
    }
    
    return null
  }
  
  bindings._get_start_icon = function(gamepad_type) {
    if (gamepad_type == 'ps3') return 'playstation3_button_start'
    if (gamepad_type == 'ps4') return 'playstation4_button_options'
    if (gamepad_type == 'ps5') return 'playstation5_button_options'
    return 'xbox_button_start'
  }
  
  // Start rebinding
  bindings.start_rebind = function(action) {
    if (!this.action_map[action]) return false
    this.is_rebinding = true
    this.rebind_target = action
    return true
  }
  
  // Complete rebinding with new control
  bindings.rebind = function(action, new_control, device_kind) {
    if (!this.action_map[action]) return false
    
    // Remove from other actions
    arrfor(array(this.action_map), act => {
      var idx = search(this.action_map[act], new_control)
      if (idx >= 0)
        this.action_map[act] = array(array(this.action_map[act], 0, idx), array(this.action_map[act], idx+1))
    })
    
    // Clear existing bindings for this device kind
    var target = this.action_map[action]
    for (var i = length(target) - 1; i >= 0; i--) {
      var existing_kind = starts_with(target[i], 'gamepad_') ? 'gamepad' :
                          starts_with(target[i], 'swipe_') ? 'touch' : 'keyboard'
      if (existing_kind == device_kind)
        this.action_map[action] = array(array(this.action_map[action], 0, i), array(this.action_map[action], i+1))
    }
    
    // Add new binding
    this.action_map[action].unshift(new_control)
    this.is_rebinding = false
    this.rebind_target = null
    return true
  }
  
  // Cancel rebinding
  bindings.cancel_rebind = function() {
    this.is_rebinding = false
    this.rebind_target = null
  }
  
  // Save bindings
  bindings.save = function(path) {
    path = path || 'keybindings.json'
    try {
      io.slurpwrite(path, json.encode(this.action_map))
      return true
    } catch(e) {
      return false
    }
  }
  
  // Load bindings
  bindings.load = function(path) {
    path = path || 'keybindings.json'
    try {
      if (io.exists(path)) {
        var data = json.decode(io.slurp(path))
        arrfor(array(data), key => {
          if (this.action_map[key]) this.action_map[key] = data[key]
        })
        return true
      }
    } catch(e) {}
    return false
  }
  
  // Reset to defaults
  bindings.reset = function() {
    arrfor(array(this._defaults), key => {
      this.action_map[key] = array(this._defaults[key])
    })
  }
  
  return bindings
}

return {
  make: make
}
