// 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 scissor clipping, foreground overlays, and blocking hit-test rects.
pub struct LayerManager {
  mut draw_list : @draw.DrawList
  fg_draw_list : @draw.DrawList
  mut fg_saved_draw_list : @draw.DrawList
  clip_stack : Array[@math.Rect]
  fg_saved_clip_stack : Array[@math.Rect]
  mut foreground_depth : Int
  blocking_rects : Array[@math.Rect]
  prev_blocking_rects : Array[@math.Rect]
} derive(Eq, Debug)

///|
pub fn LayerManager::new() -> LayerManager {
  {
    draw_list: @draw.DrawList::new(),
    fg_draw_list: @draw.DrawList::new(),
    fg_saved_draw_list: @draw.DrawList::new(),
    clip_stack: [],
    fg_saved_clip_stack: [],
    foreground_depth: 0,
    blocking_rects: [],
    prev_blocking_rects: [],
  }
}

///|
pub fn LayerManager::begin_frame(self : LayerManager) -> Unit {
  self.draw_list.clear()
  self.fg_draw_list.clear()
  self.clip_stack.clear()
  self.foreground_depth = 0
  self.prev_blocking_rects.clear()
  for rect in self.blocking_rects {
    self.prev_blocking_rects.push(rect)
  }
  self.blocking_rects.clear()
}

///|
pub fn LayerManager::push_clip(self : LayerManager, rect : @math.Rect) -> Unit {
  let effective_rect = if self.clip_stack.is_empty() {
    rect
  } else {
    let parent_clip = self.clip_stack[self.clip_stack.length() - 1]
    parent_clip.intersect(rect)
  }
  self.clip_stack.push(effective_rect)
  self.draw_list.push_clip(effective_rect)
}

///|
pub fn LayerManager::pop_clip(self : LayerManager) -> Unit {
  if !self.clip_stack.is_empty() {
    let _ = self.clip_stack.pop()
    self.draw_list.pop_clip()
  }
}

///|
pub fn LayerManager::current_clip(self : LayerManager) -> @math.Rect? {
  if self.clip_stack.is_empty() {
    None
  } else {
    Some(self.clip_stack[self.clip_stack.length() - 1])
  }
}

///|
pub fn LayerManager::begin_foreground(self : LayerManager) -> Unit {
  if self.foreground_depth == 0 {
    self.fg_saved_draw_list = self.draw_list
    self.fg_saved_clip_stack.clear()
    for rect in self.clip_stack {
      self.fg_saved_clip_stack.push(rect)
    }
    self.clip_stack.clear()
    self.draw_list = self.fg_draw_list
  }
  self.foreground_depth = self.foreground_depth + 1
}

///|
pub fn LayerManager::end_foreground(self : LayerManager) -> Unit {
  if self.foreground_depth <= 0 {
    return
  }
  self.foreground_depth = self.foreground_depth - 1
  if self.foreground_depth == 0 {
    self.draw_list = self.fg_saved_draw_list
    self.clip_stack.clear()
    for rect in self.fg_saved_clip_stack {
      self.clip_stack.push(rect)
    }
    self.fg_saved_clip_stack.clear()
  }
}

///|
pub fn LayerManager::block_hover(
  self : LayerManager,
  rect : @math.Rect,
) -> Unit {
  self.blocking_rects.push(rect)
}

///|
pub fn LayerManager::is_blocked_by_foreground(
  self : LayerManager,
  pt : @math.Vec2,
) -> Bool {
  let mut blocked = false
  for rect in self.prev_blocking_rects {
    if rect.contains(pt) {
      blocked = true
    }
  }
  blocked
}

///|
pub fn LayerManager::draw_list(self : LayerManager) -> @draw.DrawList {
  self.draw_list
}

///|
pub fn LayerManager::set_draw_list(
  self : LayerManager,
  list : @draw.DrawList,
) -> Unit {
  self.draw_list = list
}

///|
pub fn LayerManager::fg_draw_list(self : LayerManager) -> @draw.DrawList {
  self.fg_draw_list
}

///|
pub fn LayerManager::clip_stack(self : LayerManager) -> Array[@math.Rect] {
  self.clip_stack
}

///|
pub fn LayerManager::is_foreground(self : LayerManager) -> Bool {
  self.foreground_depth > 0
}