use crate::measure::{MeasuredAbsolute, MeasuredBlock, MeasuredTable};
use crate::model::{Alignment, PageSize};
use super::{LayoutImage, LayoutItem, LayoutQr, LayoutSvg};
use super::{line_alignment, layout_text_line};
use super::helpers::align_block_x;
use super::table::{row_span_groups, layout_table};

pub fn resolve_absolute_position(abs: &MeasuredAbsolute, page_size: &PageSize) -> (f32, f32) {
    let x = if abs.center_horizontal {
        (page_size.width - abs.width) / 2.0
    } else if let Some(left) = abs.left {
        if abs.right.is_some() {
            eprintln!(
                "pdfmake_rust: AbsoluteNode 同时指定了 left 和 right。left 优先，right 被忽略。"
            );
        }
        left
    } else if let Some(right) = abs.right {
        page_size.width - right - abs.width
    } else {
        0.0
    };

    let y = if abs.center_vertical {
        (page_size.height - abs.height) / 2.0
    } else if let Some(top) = abs.top {
        if abs.bottom.is_some() {
            eprintln!(
                "pdfmake_rust: AbsoluteNode 同时指定了 top 和 bottom。top 优先，bottom 被忽略。"
            );
        }
        top
    } else if let Some(bottom) = abs.bottom {
        page_size.height - bottom - abs.height
    } else {
        0.0
    };

    (x, y)
}

pub fn layout_absolute_block(
    abs: &MeasuredAbsolute,
    x: f32,
    y: f32,
) -> Vec<LayoutItem> {
    let mut items = Vec::new();
    let mut abs_y = y;

    for block in &abs.blocks {
        match block {
            MeasuredBlock::Text(text) => {
                for (line_idx, line) in text.lines.iter().enumerate() {
                    let alignment = line_alignment(line);
                    let is_last_line = line_idx == text.lines.len() - 1;
                    let is_justify = alignment == Alignment::Justify && !is_last_line;
                    let line_x = match alignment {
                        Alignment::Left | Alignment::Justify => x,
                        Alignment::Center => x + (abs.width - line.width) / 2.0,
                        Alignment::Right => x + abs.width - line.width,
                    };
                    items.push(LayoutItem::Text(layout_text_line(line, line_x, abs_y, abs.width, is_justify, text.id.clone(), text.page_reference.clone())));
                    abs_y += line.line_height;
                }
            }
            MeasuredBlock::Table(table) => {
                let groups = row_span_groups(table);
                for group in &groups {
                    let rows_for_group = if let Some(hr) = table.header_rows {
                        if group.iter().any(|&idx| idx >= hr) && group[0] >= hr {
                            let header_indices: Vec<usize> = (0..hr).collect();
                            let mut full_group = header_indices;
                            full_group.extend(group);
                            full_group
                        } else {
                            group.clone()
                        }
                    } else {
                        group.clone()
                    };

                    let actual_group_height: f32 = rows_for_group.iter().map(|&idx| table.rows[idx].height).sum();

                    let group_table = MeasuredTable {
                        column_widths: table.column_widths.clone(),
                        rows: rows_for_group.iter().map(|&idx| table.rows[idx].clone()).collect(),
                        style: table.style.clone(),
                        height: actual_group_height,
                        header_rows: table.header_rows,
                        dont_break_rows: table.dont_break_rows,
                        page_break: None,
                        heights: table.heights.clone(),
                        keep_with_header_rows: table.keep_with_header_rows,
                        table_style: table.table_style.clone(),
                        layout_config: table.layout_config.clone(),
                        h_line_when_broken: table.h_line_when_broken,
                        origin_node_idx: table.origin_node_idx,
                    };
                    items.push(LayoutItem::Table(layout_table(&group_table, x, abs_y)));
                    abs_y += actual_group_height;
                }
            }
            MeasuredBlock::Image(image) => {
                let img_x = align_block_x(x, abs.width, image.width, image.alignment);
                items.push(LayoutItem::Image(LayoutImage {
                    x: img_x, y: abs_y, width: image.width, height: image.height,
                    data: image.data.clone(),
                    format: image.format,
                    intrinsic_width: image.intrinsic_width,
                    intrinsic_height: image.intrinsic_height,
                    cover: image.cover,
                    opacity: image.opacity,
                    link: image.link.clone(),
                    link_to_page: image.link_to_page,
                    link_to_destination: image.link_to_destination.clone(),
                }));
                abs_y += image.height;
            }
            MeasuredBlock::Qr(qr) => {
                items.push(LayoutItem::Qr(LayoutQr {
                    x: x, y: abs_y, width: qr.width, height: qr.height,
                    modules: qr.modules,
                    dark_modules: qr.dark_modules.clone(),
                    foreground: qr.foreground.clone(),
                    background: qr.background.clone(),
                    padding: qr.padding,
                }));
                abs_y += qr.height;
            }
            MeasuredBlock::Svg(svg) => {
                items.push(LayoutItem::Svg(LayoutSvg {
                    x: x, y: abs_y, width: svg.width, height: svg.height,
                    view_width: svg.view_width,
                    view_height: svg.view_height,
                    shapes: svg.shapes.clone(),
                    link: svg.link.clone(),
                    link_to_page: svg.link_to_page,
                    link_to_destination: svg.link_to_destination.clone(),
                }));
                abs_y += svg.height;
            }
            _ => {}
        }
    }

    items
}
