// Copyright 2026 Ling71671
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Subsystem managing keyboard focus ring, active pointer ownership, and mouse capture.
pub struct FocusManager {
  mut hot_id : Id
  mut active_id : Id
  mut focused_id : Id
  mut prev_focused_id : Id
  mut lost_focus_id : Id
  mut pending_lost_focus_id : Id
  focusable_ids : Array[Id]
  mut wants_capture_mouse : Bool
  mut prev_wants_capture_mouse : Bool
} derive(Eq, Debug)

///|
pub fn FocusManager::new() -> FocusManager {
  {
    hot_id: Id::zero(),
    active_id: Id::zero(),
    focused_id: Id::zero(),
    prev_focused_id: Id::zero(),
    lost_focus_id: Id::zero(),
    pending_lost_focus_id: Id::zero(),
    focusable_ids: [],
    wants_capture_mouse: false,
    prev_wants_capture_mouse: false,
  }
}

///|
pub fn FocusManager::begin_frame(self : FocusManager) -> Unit {
  self.prev_focused_id = self.focused_id
  self.lost_focus_id = self.pending_lost_focus_id
  self.pending_lost_focus_id = Id::zero()
  self.focusable_ids.clear()
  self.wants_capture_mouse = false
}

///|
pub fn FocusManager::end_frame(self : FocusManager) -> Unit {
  self.prev_wants_capture_mouse = self.wants_capture_mouse
}

///|
/// Request focus for `id`. Returns `true` if focus was transferred to a new target.
pub fn FocusManager::request_focus(self : FocusManager, id : Id) -> Bool {
  if self.focused_id != id {
    if self.focused_id != Id::zero() {
      self.pending_lost_focus_id = self.focused_id
    }
    self.focused_id = id
    true
  } else {
    false
  }
}

///|
pub fn FocusManager::surrender_focus(self : FocusManager, id : Id) -> Unit {
  if self.focused_id == id {
    self.pending_lost_focus_id = id
    self.focused_id = Id::zero()
  }
}

///|
pub fn FocusManager::has_focus(self : FocusManager, id : Id) -> Bool {
  self.focused_id == id
}

///|
pub fn FocusManager::lost_focus(self : FocusManager, id : Id) -> Bool {
  self.lost_focus_id == id ||
  (self.pending_lost_focus_id == id && self.focused_id != id)
}

///|
pub fn FocusManager::register_focusable(self : FocusManager, id : Id) -> Unit {
  if !self.focusable_ids.contains(id) {
    self.focusable_ids.push(id)
  }
}

///|
pub fn FocusManager::clear_focusable(self : FocusManager) -> Unit {
  self.focusable_ids.clear()
}

///|
pub fn FocusManager::process_tab_traversal(
  self : FocusManager,
  shift : Bool,
) -> Bool {
  if self.focusable_ids.is_empty() {
    return false
  }
  let count = self.focusable_ids.length()
  let mut current_idx = -1
  for i = 0; i < count; i = i + 1 {
    if self.focusable_ids[i] == self.focused_id {
      current_idx = i
      break
    }
  }
  let next_idx = if shift {
    if current_idx <= 0 {
      count - 1
    } else {
      current_idx - 1
    }
  } else if current_idx < 0 || current_idx >= count - 1 {
    0
  } else {
    current_idx + 1
  }
  self.request_focus(self.focusable_ids[next_idx])
}

///|
pub fn FocusManager::hot_id(self : FocusManager) -> Id {
  self.hot_id
}

///|
pub fn FocusManager::set_hot_id(self : FocusManager, id : Id) -> Unit {
  self.hot_id = id
}

///|
pub fn FocusManager::active_id(self : FocusManager) -> Id {
  self.active_id
}

///|
pub fn FocusManager::set_active_id(self : FocusManager, id : Id) -> Unit {
  self.active_id = id
}

///|
pub fn FocusManager::focused_id(self : FocusManager) -> Id {
  self.focused_id
}

///|
pub fn FocusManager::set_focused_id(self : FocusManager, id : Id) -> Unit {
  self.focused_id = id
}

///|
pub fn FocusManager::prev_focused_id(self : FocusManager) -> Id {
  self.prev_focused_id
}

///|
pub fn FocusManager::wants_capture_mouse(self : FocusManager) -> Bool {
  self.wants_capture_mouse
}

///|
pub fn FocusManager::set_wants_capture_mouse(
  self : FocusManager,
  val : Bool,
) -> Unit {
  self.wants_capture_mouse = val
}

///|
pub fn FocusManager::prev_wants_capture_mouse(self : FocusManager) -> Bool {
  self.prev_wants_capture_mouse
}

///|
pub fn FocusManager::focusable_ids(self : FocusManager) -> Array[Id] {
  self.focusable_ids
}