use serde::Serialize;
use agentchrome::error::AppError;
use agentchrome::coords::BoundingBox;
use crate::cli::{GlobalOpts, PageCoordsArgs};
use crate::coord_helpers::{frame_viewport_offset, resolve_element_box};
use super::{print_output, setup_session};
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct FrameRef {
index: u32,
id: String,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct CoordPoint {
x: f64,
y: f64,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct CoordView {
bounding_box: CoordRect,
center: CoordPoint,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct CoordRect {
x: f64,
y: f64,
width: f64,
height: f64,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct CoordsOutput {
frame: FrameRef,
frame_local: CoordView,
page: CoordView,
frame_offset: CoordPoint,
}
fn bounding_box_to_rect(bb: BoundingBox) -> CoordRect {
CoordRect {
x: bb.x,
y: bb.y,
width: bb.width,
height: bb.height,
}
}
fn center_of(bb: BoundingBox) -> CoordPoint {
CoordPoint {
x: bb.x + bb.width / 2.0,
y: bb.y + bb.height / 2.0,
}
}
fn offset_bounding_box(bb: BoundingBox, offset: (f64, f64)) -> BoundingBox {
BoundingBox {
x: bb.x + offset.0,
y: bb.y + offset.1,
width: bb.width,
height: bb.height,
}
}
pub(crate) async fn execute_coords(
global: &GlobalOpts,
args: &PageCoordsArgs,
frame: Option<&str>,
) -> Result<(), AppError> {
let (client, mut managed) = setup_session(global).await?;
let mut frame_ctx =
crate::output::resolve_optional_frame(&client, &mut managed, frame, None).await?;
let frames = agentchrome::frame::list_frames(&mut managed).await?;
let (frame_index, frame_cdp_id) = if let Some(ref ctx) = frame_ctx {
let idx = frame.and_then(|f| f.parse::<u32>().ok()).unwrap_or(0);
let cdp_id = agentchrome::frame::frame_id(ctx)
.and_then(|fid| frames.iter().find(|fi| fi.id == fid))
.or_else(|| frames.iter().find(|fi| fi.index == idx))
.map(|fi| fi.id.clone())
.unwrap_or_default();
(idx, cdp_id)
} else {
let cdp_id = frames.first().map(|fi| fi.id.clone()).unwrap_or_default();
(0u32, cdp_id)
};
{
let eff_mut = if let Some(ref mut ctx) = frame_ctx {
agentchrome::frame::frame_session_mut(ctx, &mut managed)
} else {
&mut managed
};
eff_mut.ensure_domain("DOM").await?;
eff_mut.ensure_domain("Runtime").await?;
}
let local_box = resolve_element_box(&managed, frame_ctx.as_ref(), &args.selector).await?;
let (off_x, off_y) = if let Some(ref ctx) = frame_ctx {
frame_viewport_offset(&managed, ctx).await?
} else {
(0.0, 0.0)
};
let page_box = offset_bounding_box(local_box, (off_x, off_y));
let output = CoordsOutput {
frame: FrameRef {
index: frame_index,
id: frame_cdp_id,
},
frame_local: CoordView {
bounding_box: bounding_box_to_rect(local_box),
center: center_of(local_box),
},
page: CoordView {
bounding_box: bounding_box_to_rect(page_box),
center: center_of(page_box),
},
frame_offset: CoordPoint { x: off_x, y: off_y },
};
print_output(&output, &global.output)
}