const std = @import("std");
const Document = @import("../../models/Document.zig");
const pipeline = @import("pipeline.zig");
const line = @import("line.zig");
const ellipse = @import("ellipse.zig");
const broken = @import("broken.zig");
const basic_models = @import("../../models/basic_models.zig");
const Rect_i = basic_models.Rect_i;
const Size_i = basic_models.Size_i;

const Object = Document.Object;
const DrawContext = pipeline.DrawContext;
const Transform = pipeline.Transform;

fn isVisible(obj: *const Object) bool {
    return obj.getProperty(.visible) orelse true;
}

fn drawObject(
    ctx: *DrawContext,
    obj: *const Object,
    parent_transform: Transform,
    allocator: std.mem.Allocator,
) !void {
    if (!isVisible(obj)) return;
    const local = Transform.init(obj);
    const world = Transform.compose(parent_transform, local);
    ctx.setTransform(world);

    switch (obj.shape) {
        .line => line.draw(ctx, obj),
        .ellipse => try ellipse.draw(ctx, obj, allocator),
        .broken => try broken.draw(ctx, obj, allocator),
    }

    for (obj.children.items) |*child| {
        try drawObject(ctx, child, world, allocator);
    }
}

/// Рекурсивно рисует документ в буфер (объекты и потомки по порядку).
/// allocator опционален; если передан, ломаные рисуются через слой (без двойного наложения при alpha < 1).
pub fn drawDocument(
    pixels: []@import("dvui").Color.PMA,
    buf_width: u32,
    buf_height: u32,
    visible_rect: Rect_i,
    document: *const Document,
    canvas_size: Size_i,
    allocator: std.mem.Allocator,
) !void {
    const scale_x: f32 = if (document.size.w > 0) @as(f32, @floatFromInt(canvas_size.w)) / document.size.w else 0;
    const scale_y: f32 = if (document.size.h > 0) @as(f32, @floatFromInt(canvas_size.h)) / document.size.h else 0;

    var ctx = DrawContext{
        .pixels = pixels,
        .buf_width = buf_width,
        .buf_height = buf_height,
        .visible_rect = visible_rect,
        .scale_x = scale_x,
        .scale_y = scale_y,
    };
    const identity = Transform{};
    for (document.objects.items) |*obj| {
        try drawObject(&ctx, obj, identity, allocator);
    }
}
