// Prosperon Input System
// Engine-driven input with user pairing and possession dispatch

var backend = use('input/backends/sdl3')
var devices = use('input/devices')
var bindings_mod = use('input/bindings')
var router_mod = use('input/router')

// Default UI-focused action map
var default_action_map = {
  'ui_up': ['w', 'up', 'gamepad_dpup'],
  'ui_down': ['s', 'down', 'gamepad_dpdown'],
  'ui_left': ['a', 'left', 'gamepad_dpleft'],
  'ui_right': ['d', 'right', 'gamepad_dpright'],
  'confirm': ['return', 'space', 'mouse_button_left', 'gamepad_a'],
  'cancel': ['escape', 'gamepad_b'],
  'menu': ['escape', 'gamepad_start']
}

var default_display_names = {
  'ui_up': 'UI Up',
  'ui_down': 'UI Down',
  'ui_left': 'UI Left',
  'ui_right': 'UI Right',
  'confirm': 'Confirm',
  'cancel': 'Cancel',
  'menu': 'Menu'
}

// Module state
var _users = []
var _config = {
  max_users: 1,
  pairing: 'last_used',
  emacs: true,
  gestures: true,
  action_map: default_action_map,
  display_names: default_display_names
}

var _initialized = false
var _window_callback = null

// Create an input user
function create_user(index, config) {
  var action_map = {}
  var display_names = {}
  
  // Merge defaults with config
  arrfor(array(default_action_map), function(k) {
    action_map[k] = array(default_action_map[k])
    display_names[k] = default_display_names[k]
  })
  if (config.action_map) {
    arrfor(array(config.action_map), function(k) {
      var val = config.action_map[k]
      action_map[k] = is_array(val) ? array(val) : [val]
    })
  }
  if (config.display_names) {
    arrfor(array(config.display_names), k => display_names[k] = config.display_names[k])
  }
  
  var user = {
    index: index,
    paired_devices: [],
    active_device: null,
    bindings: bindings_mod.make(action_map, display_names),
    router: null,
    control_stack: [],
    
    // Get current device kind
    get device_kind() {
      if (!this.active_device) return 'keyboard'
      return devices.kind(this.active_device)
    },
    
    // Get current gamepad type
    get gamepad_type() {
      if (!this.active_device) return null
      return devices.gamepad_type(this.active_device)
    },
    
    // Get action down state
    get down() {
      return this.router ? this.router.down : {}
    },
    
    // Possess an entity (clears stack, sets as sole target)
    possess: function(entity) {
      this.control_stack = [entity]
    },
    
    // Push entity onto control stack
    push: function(entity) {
      push(this.control_stack, entity)
    },
    
    // Pop from control stack
    pop: function() {
      if (length(this.control_stack) > 1) {
        return pop(this.control_stack)
      }
      return null
    },
    
    // Get current control target
    get target() {
      return length(this.control_stack) > 0 
        ? this.control_stack[length(this.control_stack) - 1] 
        : null
    },
    
    // Dispatch action to current target
    dispatch: function(action, data) {
      var target = this.target
      if (target && target.on_input) {
        target.on_input(action, data)
      }
    },
    
    // Get icon for action using current device
    get_icon_for_action: function(action) {
      return this.bindings.get_icon_for_action(action, this.device_kind, this.gamepad_type)
    },
    
    // Get primary binding for action using current device
    get_primary_binding: function(action) {
      return this.bindings.get_primary_binding(action, this.device_kind)
    }
  }
  
  // Create router
  user.router = router_mod.make(user, {
    emacs: config.emacs,
    gestures: config.gestures,
    swipe_min_dist: config.swipe_min_dist,
    swipe_max_time: config.swipe_max_time,
    pinch_threshold: config.pinch_threshold
  })
  
  // Load saved bindings
  user.bindings.load()
  
  return user
}

// Pick user based on pairing policy
function pick_user(canon) {
  if (length(_users) == 0) return null
  
  // For last_used: always user 0, just update active device
  if (_config.pairing == 'last_used') {
    var user = _users[0]
    
    // Only switch on button press, not axis/motion
    if (canon.kind == 'button' && canon.pressed) {
      if (user.active_device != canon.device_id) {
        // Release all held actions when switching device
        var old_down = user.router.down
        arrfor(array(old_down), action => {
          if (old_down[action]) {
            user.dispatch(action, { pressed: false, released: true, time: canon.time })
          }
        })
        
        user.active_device = canon.device_id
        if (find(user.paired_devices, canon.device_id) == null) {
          push(user.paired_devices, canon.device_id)
        }
      }
    }
    
    return user
  }
  
  // For explicit pairing: find user paired to this device
  for (var i = 0; i < length(_users); i++) {
    if (find(_users[i].paired_devices, canon.device_id) != null) {
      _users[i].active_device = canon.device_id
      return _users[i]
    }
  }
  
  // Unpaired device - could implement join logic here
  return null
}

// Configure the input system
function configure(opts) {
  opts = opts || {}
  
  _config.max_users = opts.max_users || 1
  _config.pairing = opts.pairing || 'last_used'
  _config.emacs = opts.emacs != false
  _config.gestures = opts.gestures != false
  
  if (opts.action_map) _config.action_map = opts.action_map
  if (opts.display_names) _config.display_names = opts.display_names
  if (opts.on_window) _window_callback = opts.on_window
  
  // Copy gesture config
  _config.swipe_min_dist = opts.swipe_min_dist
  _config.swipe_max_time = opts.swipe_max_time
  _config.pinch_threshold = opts.pinch_threshold
  
  // Create users
  _users = []
  for (var i = 0; i < _config.max_users; i++) {
    push(_users, create_user(i, _config))
  }
  
  _initialized = true
}

// Ingest a raw SDL event
function ingest(raw_evt) {
  if (!_initialized) {
    configure({})
  }
  
  // Translate to canonical format
  var canon = backend.translate(raw_evt)
  if (!canon) return
  
  // Handle window events specially
  if (canon.kind == 'window') {
    if (_window_callback) {
      _window_callback(canon)
    }
    return
  }
  
  // Handle device events
  if (canon.kind == 'device') {
    if (canon.control == 'connected') {
      devices.register(canon)
    } else if (canon.control == 'disconnected') {
      devices.unregister(canon.device_id)
    }
    return
  }
  
  // Register device
  devices.register(canon)
  
  // Pick user and route
  var user = pick_user(canon)
  if (user) {
    user.router.handle(canon)
  }
}

// Get user by index
function user(index) {
  return _users[index]
}

return {
  configure: configure,
  ingest: ingest,
  user: user,
  
  get player1() { return _users[0] },
  get player2() { return _users[1] },
  get player3() { return _users[2] },
  get player4() { return _users[3] },
  
  // Re-export for convenience
  devices: devices,
  backend: backend
}