use std::cell::LazyCell;
use typst_library::diag::SourceResult;
use typst_library::engine::Engine;
use typst_library::foundations::{Packed, StyleChain};
use typst_library::introspection::Locator;
use typst_library::layout::{BoxElem, Frame, FrameKind, Size};
use typst_library::visualize::Stroke;
use typst_utils::Numeric;
use crate::flow::unbreakable_pod;
use crate::shapes::{clip_rect, fill_and_stroke};
#[typst_macros::time(name = "box", span = elem.span())]
pub fn layout_box(
elem: &Packed<BoxElem>,
engine: &mut Engine,
locator: Locator,
styles: StyleChain,
region: Size,
) -> SourceResult<Frame> {
let width = elem.width.get(styles);
let height = elem.height.get(styles);
let inset = elem.inset.resolve(styles).unwrap_or_default();
let pod = unbreakable_pod(&width, &height.into(), &inset, styles, region);
let mut frame = match elem.body.get_ref(styles) {
None => Frame::hard(Size::zero()),
Some(body) => crate::layout_frame(engine, body, locator, styles, pod)?
.with_kind(FrameKind::Hard),
};
frame.set_size(pod.expand.select(pod.size, frame.size()));
if !inset.is_zero() {
crate::pad::grow(&mut frame, &inset);
}
let fill = elem.fill.get_cloned(styles);
let stroke = elem
.stroke
.resolve(styles)
.unwrap_or_default()
.map(|s| s.map(Stroke::unwrap_or_default));
let outset = LazyCell::new(|| elem.outset.resolve(styles).unwrap_or_default());
let radius = LazyCell::new(|| elem.radius.resolve(styles).unwrap_or_default());
if elem.clip.get(styles) {
frame.clip(clip_rect(frame.size(), &radius, &stroke, &outset));
}
if fill.is_some() || stroke.iter().any(Option::is_some) {
fill_and_stroke(&mut frame, fill, &stroke, &outset, &radius, elem.span());
}
if let Some(label) = elem.label() {
frame.label(label);
}
let shift = elem.baseline.resolve(styles).relative_to(frame.height());
if !shift.is_zero() {
frame.set_baseline(frame.baseline() - shift);
}
Ok(frame)
}