use super::utils::{write_f32, write_pdf};
use std::io::Write;

pub fn svg_fill_color(buf: &mut Vec<u8>, color: &str) {
    if let Some((r, g, b)) = crate::color::parse_color(color) {
        write_pdf!(buf, "{:.2} {:.2} {:.2} rg\n", r, g, b);
    }
}

/// 生成设置描边色的 PDF 指令 (RGB)
pub fn svg_stroke_color(buf: &mut Vec<u8>, color: &str) {
    if let Some((r, g, b)) = crate::color::parse_color(color) {
        write_pdf!(buf, "{:.2} {:.2} {:.2} RG\n", r, g, b);
    }
}

pub fn render_svg_item(page_height: f32, svg: &crate::layout::LayoutSvg) -> Vec<u8> {
    let mut stream = Vec::with_capacity(512);
    let sx = svg.width / svg.view_width;
    let sy = svg.height / svg.view_height;
    let _gradient_index = 0usize;
    stream.extend_from_slice(b"q\n");
    stream.extend_from_slice(b"0 g\n");
    for shape in &svg.shapes {
        match shape {
            crate::vector::VectorShape::Rect { x, y, width, height, fill, stroke, stroke_width, line_join, line_cap, dash_array, .. } => {
                let px = svg.x + x * sx;
                let py = page_height - svg.y - (y + height) * sy;
                let pw = width * sx;
                let ph = height * sy;

                // Set line styles
                if let Some(lj) = line_join {
                    match lj.as_str() {
                        "miter" => stream.extend_from_slice(b"0 j\n"),
                        "round" => stream.extend_from_slice(b"1 j\n"),
                        "bevel" => stream.extend_from_slice(b"2 j\n"),
                        _ => {}
                    }
                }
                if let Some(lc) = line_cap {
                    match lc.as_str() {
                        "butt" => stream.extend_from_slice(b"0 J\n"),
                        "round" => stream.extend_from_slice(b"1 J\n"),
                        "square" => stream.extend_from_slice(b"2 J\n"),
                        _ => {}
                    }
                }
                if let Some(dash) = dash_array {
                    let parts: Vec<f32> = dash.split(',').filter_map(|s| s.trim().parse().ok()).collect();
                    if !parts.is_empty() {
                        stream.extend_from_slice(b"[");
                        for (i, val) in parts.iter().enumerate() {
                            if i > 0 { stream.push(b' '); }
                            write_f32(&mut stream, *val, 2);
                        }
                        stream.extend_from_slice(b"] 0 d\n");
                    }
                }

                match fill {
                    Some(c) if c != "none" => svg_fill_color(&mut stream, c),
                    _ => stream.extend_from_slice(b"n\n"),
                }
                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }
                if let Some(w) = stroke_width {
                    write_pdf!(stream, "{:.2} w\n", w * sx);
                }

                write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re\n", px, py, pw, ph);

                let has_fill = fill.as_ref().map(|c| c != "none").unwrap_or(false);
                let has_stroke = stroke.is_some();
                match (has_fill, has_stroke) {
                    (true, true) => stream.extend_from_slice(b"B\n"),
                    (true, false) => stream.extend_from_slice(b"f\n"),
                    (false, true) => stream.extend_from_slice(b"S\n"),
                    (false, false) => stream.extend_from_slice(b"n\n"),
                }

                // Reset line styles
                stream.extend_from_slice(b"0 j 0 J [] 0 d\n");
            }
            crate::vector::VectorShape::Line { x1, y1, x2, y2, stroke, stroke_width, line_join, line_cap, dash_array, .. } => {
                let px1 = svg.x + x1 * sx;
                let py1 = page_height - svg.y - y1 * sy;
                let px2 = svg.x + x2 * sx;
                let py2 = page_height - svg.y - y2 * sy;

                // Set line styles
                if let Some(lj) = line_join {
                    match lj.as_str() {
                        "miter" => stream.extend_from_slice(b"0 j\n"),
                        "round" => stream.extend_from_slice(b"1 j\n"),
                        "bevel" => stream.extend_from_slice(b"2 j\n"),
                        _ => {}
                    }
                }
                if let Some(lc) = line_cap {
                    match lc.as_str() {
                        "butt" => stream.extend_from_slice(b"0 J\n"),
                        "round" => stream.extend_from_slice(b"1 J\n"),
                        "square" => stream.extend_from_slice(b"2 J\n"),
                        _ => {}
                    }
                }
                if let Some(dash) = dash_array {
                    let parts: Vec<f32> = dash.split(',').filter_map(|s| s.trim().parse().ok()).collect();
                    if !parts.is_empty() {
                        stream.extend_from_slice(b"[");
                        for (i, val) in parts.iter().enumerate() {
                            if i > 0 { stream.push(b' '); }
                            write_f32(&mut stream, *val, 2);
                        }
                        stream.extend_from_slice(b"] 0 d\n");
                    }
                }

                let w = stroke_width.unwrap_or(0.5) * sx;
                write_pdf!(stream, "{:.2} w\n", w);

                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }

                write_pdf!(stream, "{:.2} {:.2} m {:.2} {:.2} l S\n", px1, py1, px2, py2);

                // Reset line styles
                stream.extend_from_slice(b"0 j 0 J [] 0 d\n");
            }
            crate::vector::VectorShape::Circle { cx, cy, r, fill, stroke, stroke_width, line_join, line_cap, dash_array, .. } => {
                let pcx = svg.x + cx * sx;
                let pcy = page_height - svg.y - cy * sy;
                let pr = r * sx.min(sy);

                let c = pr * 0.552_284_8;

                // Set line styles
                if let Some(lj) = line_join {
                    match lj.as_str() {
                        "miter" => stream.extend_from_slice(b"0 j\n"),
                        "round" => stream.extend_from_slice(b"1 j\n"),
                        "bevel" => stream.extend_from_slice(b"2 j\n"),
                        _ => {}
                    }
                }
                if let Some(lc) = line_cap {
                    match lc.as_str() {
                        "butt" => stream.extend_from_slice(b"0 J\n"),
                        "round" => stream.extend_from_slice(b"1 J\n"),
                        "square" => stream.extend_from_slice(b"2 J\n"),
                        _ => {}
                    }
                }
                if let Some(dash) = dash_array {
                    let parts: Vec<f32> = dash.split(',').filter_map(|s| s.trim().parse().ok()).collect();
                    if !parts.is_empty() {
                        stream.extend_from_slice(b"[");
                        for (i, val) in parts.iter().enumerate() {
                            if i > 0 { stream.push(b' '); }
                            write_f32(&mut stream, *val, 2);
                        }
                        stream.extend_from_slice(b"] 0 d\n");
                    }
                }

                match fill {
                    Some(c) if c != "none" => svg_fill_color(&mut stream, c),
                    _ => stream.extend_from_slice(b"n\n"),
                }
                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }
                if let Some(w) = stroke_width {
                    write_pdf!(stream, "{:.2} w\n", w * sx);
                }

                write_pdf!(stream,
                    "{:.2} {:.2} m {:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c {:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c {:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c {:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n",
                    pcx + pr, pcy,
                    pcx + pr, pcy + c, pcx + c, pcy + pr, pcx, pcy + pr,
                    pcx - c, pcy + pr, pcx - pr, pcy + c, pcx - pr, pcy,
                    pcx - pr, pcy - c, pcx - c, pcy - pr, pcx, pcy - pr,
                    pcx + c, pcy - pr, pcx + pr, pcy - c, pcx + pr, pcy
                );

                let has_fill = fill.as_ref().map(|c| c != "none").unwrap_or(false);
                let has_stroke = stroke.is_some();
                match (has_fill, has_stroke) {
                    (true, true) => stream.extend_from_slice(b"B\n"),
                    (true, false) => stream.extend_from_slice(b"f\n"),
                    (false, true) => stream.extend_from_slice(b"S\n"),
                    (false, false) => stream.extend_from_slice(b"n\n"),
                }

                // Reset line styles
                stream.extend_from_slice(b"0 j 0 J [] 0 d\n");
            }
            crate::vector::VectorShape::Ellipse { cx, cy, rx, ry, fill, stroke, stroke_width, line_join, line_cap, dash_array, .. } => {
                let pcx = svg.x + cx * sx;
                let pcy = page_height - svg.y - cy * sy;
                let prx = rx * sx;
                let pry = ry * sy;

                let k = 0.552_284_8;
                let kx = prx * k;
                let ky = pry * k;

                // Set line styles
                if let Some(lj) = line_join {
                    match lj.as_str() {
                        "miter" => stream.extend_from_slice(b"0 j\n"),
                        "round" => stream.extend_from_slice(b"1 j\n"),
                        "bevel" => stream.extend_from_slice(b"2 j\n"),
                        _ => {}
                    }
                }
                if let Some(lc) = line_cap {
                    match lc.as_str() {
                        "butt" => stream.extend_from_slice(b"0 J\n"),
                        "round" => stream.extend_from_slice(b"1 J\n"),
                        "square" => stream.extend_from_slice(b"2 J\n"),
                        _ => {}
                    }
                }
                if let Some(dash) = dash_array {
                    let parts: Vec<f32> = dash.split(',').filter_map(|s| s.trim().parse().ok()).collect();
                    if !parts.is_empty() {
                        stream.extend_from_slice(b"[");
                        for (i, val) in parts.iter().enumerate() {
                            if i > 0 { stream.push(b' '); }
                            write_f32(&mut stream, *val, 2);
                        }
                        stream.extend_from_slice(b"] 0 d\n");
                    }
                }

                match fill {
                    Some(c) if c != "none" => svg_fill_color(&mut stream, c),
                    _ => {}
                }
                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }
                if let Some(w) = stroke_width {
                    write_pdf!(stream, "{:.2} w\n", w * sx);
                }

                write_pdf!(stream, "{:.2} {:.2} m\n", pcx + prx, pcy);
                write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n",
                    pcx + prx, pcy + ky, pcx + kx, pcy + pry, pcx, pcy + pry);
                write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n",
                    pcx - kx, pcy + pry, pcx - prx, pcy + ky, pcx - prx, pcy);
                write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n",
                    pcx - prx, pcy - ky, pcx - kx, pcy - pry, pcx, pcy - pry);
                write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n",
                    pcx + kx, pcy - pry, pcx + prx, pcy - ky, pcx + prx, pcy);

                let has_fill = fill.as_ref().map(|c| c != "none").unwrap_or(false);
                let has_stroke = stroke.is_some();
                match (has_fill, has_stroke) {
                    (true, true) => stream.extend_from_slice(b"B\n"),
                    (true, false) => stream.extend_from_slice(b"f\n"),
                    (false, true) => stream.extend_from_slice(b"S\n"),
                    (false, false) => stream.extend_from_slice(b"n\n"),
                }

                // Reset line styles
                stream.extend_from_slice(b"0 j 0 J [] 0 d\n");
            }
            crate::vector::VectorShape::Path { commands, fill, stroke, stroke_width, fill_rule, .. } => {
                if let Some(c) = fill.as_ref().filter(|c| *c != "none") {
                    svg_fill_color(&mut stream, c);
                }
                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }
                if let Some(w) = stroke_width {
                    write_pdf!(stream, "{:.2} w\n", w * sx);
                }

                let mut cx = 0.0f32;
                let mut cy = 0.0f32;
                let mut subpath_start_x = 0.0f32;
                let mut subpath_start_y = 0.0f32;
                // Track last control point for S/s smooth curve commands
                let mut last_cpx = 0.0f32;
                let mut last_cpy = 0.0f32;
                let mut last_cmd_was_curve = false;

                for cmd in commands {
                    // Reset curve tracking for non-curve commands (will be set true by curve commands)
                    let is_curve = matches!(cmd,
                        crate::vector::PathCommand::CurveTo { .. } |
                        crate::vector::PathCommand::RelativeCurveTo { .. } |
                        crate::vector::PathCommand::SmoothCurveTo { .. } |
                        crate::vector::PathCommand::RelativeSmoothCurveTo { .. }
                    );
                    match cmd {
                        crate::vector::PathCommand::MoveTo { x, y } => {
                            let px = svg.x + x * sx;
                            let py = page_height - svg.y - y * sy;
                            write_pdf!(stream, "{:.2} {:.2} m\n", px, py);
                            cx = *x; cy = *y;
                            subpath_start_x = *x; subpath_start_y = *y;
                        }
                        crate::vector::PathCommand::RelativeMoveTo { dx, dy } => {
                            cx += dx; cy += dy;
                            let px = svg.x + cx * sx;
                            let py = page_height - svg.y - cy * sy;
                            write_pdf!(stream, "{:.2} {:.2} m\n", px, py);
                            subpath_start_x = cx; subpath_start_y = cy;
                        }
                        crate::vector::PathCommand::LineTo { x, y } => {
                            let px = svg.x + x * sx;
                            let py = page_height - svg.y - y * sy;
                            write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                            cx = *x; cy = *y;
                        }
                        crate::vector::PathCommand::RelativeLineTo { dx, dy } => {
                            cx += dx; cy += dy;
                            let px = svg.x + cx * sx;
                            let py = page_height - svg.y - cy * sy;
                            write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                        }
                        crate::vector::PathCommand::HorizontalLineTo { x } => {
                            let px = svg.x + x * sx;
                            let py = page_height - svg.y - cy * sy;
                            write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                            cx = *x;
                        }
                        crate::vector::PathCommand::RelativeHorizontalLineTo { dx } => {
                            cx += dx;
                            let px = svg.x + cx * sx;
                            let py = page_height - svg.y - cy * sy;
                            write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                        }
                        crate::vector::PathCommand::VerticalLineTo { y } => {
                            let px = svg.x + cx * sx;
                            let py = page_height - svg.y - y * sy;
                            write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                            cy = *y;
                        }
                        crate::vector::PathCommand::RelativeVerticalLineTo { dy } => {
                            cy += dy;
                            let px = svg.x + cx * sx;
                            let py = page_height - svg.y - cy * sy;
                            write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                        }
                        crate::vector::PathCommand::CurveTo { x1, y1, x2, y2, x, y } => {
                            let px1 = svg.x + x1 * sx; let py1 = page_height - svg.y - y1 * sy;
                            let px2 = svg.x + x2 * sx; let py2 = page_height - svg.y - y2 * sy;
                            let px = svg.x + x * sx; let py = page_height - svg.y - y * sy;
                            write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", px1, py1, px2, py2, px, py);
                            last_cpx = *x2; last_cpy = *y2;
                            last_cmd_was_curve = true;
                            cx = *x; cy = *y;
                        }
                        crate::vector::PathCommand::RelativeCurveTo { dx1, dy1, dx2, dy2, dx, dy } => {
                            let px1 = svg.x + (cx + dx1) * sx; let py1 = page_height - svg.y - (cy + dy1) * sy;
                            let px2 = svg.x + (cx + dx2) * sx; let py2 = page_height - svg.y - (cy + dy2) * sy;
                            let px = svg.x + (cx + dx) * sx; let py = page_height - svg.y - (cy + dy) * sy;
                            write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", px1, py1, px2, py2, px, py);
                            last_cpx = cx + dx2; last_cpy = cy + dy2;
                            last_cmd_was_curve = true;
                            cx += dx; cy += dy;
                        }
                        crate::vector::PathCommand::SmoothCurveTo { x2, y2, x, y } => {
                            // Reflect the last control point around current point
                            let (cp1x, cp1y) = if last_cmd_was_curve {
                                (2.0 * cx - last_cpx, 2.0 * cy - last_cpy)
                            } else {
                                (cx, cy)
                            };
                            let px1 = svg.x + cp1x * sx; let py1 = page_height - svg.y - cp1y * sy;
                            let px2 = svg.x + x2 * sx; let py2 = page_height - svg.y - y2 * sy;
                            let px = svg.x + x * sx; let py = page_height - svg.y - y * sy;
                            write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", px1, py1, px2, py2, px, py);
                            last_cpx = *x2; last_cpy = *y2;
                            last_cmd_was_curve = true;
                            cx = *x; cy = *y;
                        }
                        crate::vector::PathCommand::RelativeSmoothCurveTo { dx2, dy2, dx, dy } => {
                            let (cp1x, cp1y) = if last_cmd_was_curve {
                                (2.0 * cx - last_cpx, 2.0 * cy - last_cpy)
                            } else {
                                (cx, cy)
                            };
                            let px1 = svg.x + cp1x * sx; let py1 = page_height - svg.y - cp1y * sy;
                            let px2 = svg.x + (cx + dx2) * sx; let py2 = page_height - svg.y - (cy + dy2) * sy;
                            let px = svg.x + (cx + dx) * sx; let py = page_height - svg.y - (cy + dy) * sy;
                            write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", px1, py1, px2, py2, px, py);
                            last_cpx = cx + dx2; last_cpy = cy + dy2;
                            last_cmd_was_curve = true;
                            cx += dx; cy += dy;
                        }
                        crate::vector::PathCommand::QuadraticCurveTo { x1, y1, x, y } => {
                            let px1 = svg.x + x1 * sx; let py1 = page_height - svg.y - y1 * sy;
                            let px = svg.x + x * sx; let py = page_height - svg.y - y * sy;
                            write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", px1, py1, px1, py1, px, py);
                            cx = *x; cy = *y;
                        }
                        crate::vector::PathCommand::RelativeQuadraticCurveTo { dx1, dy1, dx, dy } => {
                            let px1 = svg.x + (cx + dx1) * sx; let py1 = page_height - svg.y - (cy + dy1) * sy;
                            let px = svg.x + (cx + dx) * sx; let py = page_height - svg.y - (cy + dy) * sy;
                            write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", px1, py1, px1, py1, px, py);
                            cx += dx; cy += dy;
                        }
                        crate::vector::PathCommand::SmoothQuadraticCurveTo { x, y } => {
                            let px = svg.x + x * sx; let py = page_height - svg.y - y * sy;
                            let px1 = svg.x + cx * sx; let py1 = page_height - svg.y - cy * sy;
                            write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", px1, py1, px1, py1, px, py);
                            cx = *x; cy = *y;
                        }
                        crate::vector::PathCommand::RelativeSmoothQuadraticCurveTo { dx, dy } => {
                            let px = svg.x + (cx + dx) * sx; let py = page_height - svg.y - (cy + dy) * sy;
                            let px1 = svg.x + cx * sx; let py1 = page_height - svg.y - cy * sy;
                            write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", px1, py1, px1, py1, px, py);
                            cx += dx; cy += dy;
                        }
                        crate::vector::PathCommand::Arc { x, y, .. } => {
                            let px = svg.x + x * sx;
                            let py = page_height - svg.y - y * sy;
                            write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                            cx = *x; cy = *y;
                        }
                        crate::vector::PathCommand::RelativeArc { dx, dy, .. } => {
                            cx += dx; cy += dy;
                            let px = svg.x + cx * sx;
                            let py = page_height - svg.y - cy * sy;
                            write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                        }
                        crate::vector::PathCommand::ClosePath => {
                            stream.extend_from_slice(b"h\n");
                            cx = subpath_start_x;
                            cy = subpath_start_y;
                        }
                    }
                    if !is_curve {
                        last_cmd_was_curve = false;
                    }
                }

                let has_fill = fill.as_ref().map(|c| c != "none").unwrap_or(false);
                let has_stroke = stroke.is_some();
                let fill_op = match fill_rule {
                    crate::vector::FillRule::EvenOdd => b"f*\n" as &[u8],
                    crate::vector::FillRule::NonZero => b"f\n",
                };
                match (has_fill, has_stroke) {
                    (true, true) => stream.extend_from_slice(b"B\n"),
                    (true, false) => stream.extend_from_slice(fill_op),
                    (false, true) => stream.extend_from_slice(b"S\n"),
                    (false, false) => stream.extend_from_slice(b"n\n"),
                }
            }
            crate::vector::VectorShape::Polyline { points, fill, stroke, stroke_width, line_join, line_cap, dash_array, .. } => {
                // Set line styles
                if let Some(lj) = line_join {
                    match lj.as_str() {
                        "miter" => stream.extend_from_slice(b"0 j\n"),
                        "round" => stream.extend_from_slice(b"1 j\n"),
                        "bevel" => stream.extend_from_slice(b"2 j\n"),
                        _ => {}
                    }
                }
                if let Some(lc) = line_cap {
                    match lc.as_str() {
                        "butt" => stream.extend_from_slice(b"0 J\n"),
                        "round" => stream.extend_from_slice(b"1 J\n"),
                        "square" => stream.extend_from_slice(b"2 J\n"),
                        _ => {}
                    }
                }
                if let Some(dash) = dash_array {
                    let parts: Vec<f32> = dash.split(',').filter_map(|s| s.trim().parse().ok()).collect();
                    if !parts.is_empty() {
                        stream.extend_from_slice(b"[");
                        for (i, val) in parts.iter().enumerate() {
                            if i > 0 { stream.push(b' '); }
                            write_f32(&mut stream, *val, 2);
                        }
                        stream.extend_from_slice(b"] 0 d\n");
                    }
                }

                if let Some(c) = fill.as_ref().filter(|c| *c != "none") {
                    svg_fill_color(&mut stream, c);
                }
                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }
                if let Some(w) = stroke_width {
                    write_pdf!(stream, "{:.2} w\n", w * sx);
                }

                for (i, pt) in points.iter().enumerate() {
                    let px = svg.x + pt.0 * sx;
                    let py = page_height - svg.y - pt.1 * sy;
                    if i == 0 {
                        write_pdf!(stream, "{:.2} {:.2} m\n", px, py);
                    } else {
                        write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                    }
                }

                let has_fill = fill.as_ref().map(|c| c != "none").unwrap_or(false);
                let has_stroke = stroke.is_some();
                match (has_fill, has_stroke) {
                    (true, true) => stream.extend_from_slice(b"B\n"),
                    (true, false) => stream.extend_from_slice(b"f\n"),
                    (false, true) => stream.extend_from_slice(b"S\n"),
                    (false, false) => stream.extend_from_slice(b"n\n"),
                }

                // Reset line styles
                stream.extend_from_slice(b"0 j 0 J [] 0 d\n");
            }
            crate::vector::VectorShape::Polygon { points, fill, stroke, stroke_width, line_join, line_cap, dash_array, .. } => {
                // Set line styles
                if let Some(lj) = line_join {
                    match lj.as_str() {
                        "miter" => stream.extend_from_slice(b"0 j\n"),
                        "round" => stream.extend_from_slice(b"1 j\n"),
                        "bevel" => stream.extend_from_slice(b"2 j\n"),
                        _ => {}
                    }
                }
                if let Some(lc) = line_cap {
                    match lc.as_str() {
                        "butt" => stream.extend_from_slice(b"0 J\n"),
                        "round" => stream.extend_from_slice(b"1 J\n"),
                        "square" => stream.extend_from_slice(b"2 J\n"),
                        _ => {}
                    }
                }
                if let Some(dash) = dash_array {
                    let parts: Vec<f32> = dash.split(',').filter_map(|s| s.trim().parse().ok()).collect();
                    if !parts.is_empty() {
                        stream.extend_from_slice(b"[");
                        for (i, val) in parts.iter().enumerate() {
                            if i > 0 { stream.push(b' '); }
                            write_f32(&mut stream, *val, 2);
                        }
                        stream.extend_from_slice(b"] 0 d\n");
                    }
                }

                if let Some(c) = fill.as_ref().filter(|c| *c != "none") {
                    svg_fill_color(&mut stream, c);
                }
                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }
                if let Some(w) = stroke_width {
                    write_pdf!(stream, "{:.2} w\n", w * sx);
                }

                for (i, pt) in points.iter().enumerate() {
                    let px = svg.x + pt.0 * sx;
                    let py = page_height - svg.y - pt.1 * sy;
                    if i == 0 {
                        write_pdf!(stream, "{:.2} {:.2} m\n", px, py);
                    } else {
                        write_pdf!(stream, "{:.2} {:.2} l\n", px, py);
                    }
                }
                stream.extend_from_slice(b"h\n");

                let has_fill = fill.as_ref().map(|c| c != "none").unwrap_or(false);
                let has_stroke = stroke.is_some();
                match (has_fill, has_stroke) {
                    (true, true) => stream.extend_from_slice(b"B\n"),
                    (true, false) => stream.extend_from_slice(b"f\n"),
                    (false, true) => stream.extend_from_slice(b"S\n"),
                    (false, false) => stream.extend_from_slice(b"n\n"),
                }

                // Reset line styles
                stream.extend_from_slice(b"0 j 0 J [] 0 d\n");
            }
            crate::vector::VectorShape::LinearGradient { x, y, width, height, x1: _, y1: _, x2: _, y2: _, stops, stroke, stroke_width } => {
                let px = svg.x + x * sx;
                let py = page_height - svg.y - (y + height) * sy;
                let pw = width * sx;
                let ph = height * sy;

                // Approximate gradient with horizontal color strips
                let num_strips = stops.len().max(2).min(50);
                let strip_h = ph / num_strips as f32;
                for i in 0..num_strips {
                    let t = (i as f32 + 0.5) / num_strips as f32;
                    // Interpolate color from stops
                    let (r, g, b) = interpolate_gradient_stops(stops, t);
                    write_pdf!(stream, "{:.3} {:.3} {:.3} rg\n", r, g, b);
                    let sy_pos = py + i as f32 * strip_h;
                    write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re f\n", px, sy_pos, pw, strip_h + 0.5);
                }

                // Draw stroke if specified
                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }
                if let Some(w) = stroke_width {
                    write_pdf!(stream, "{:.2} w\n", w * sx);
                }
                if stroke.is_some() {
                    write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re S\n", px, py, pw, ph);
                }
                stream.extend_from_slice(b"0 g\n");
            }
            crate::vector::VectorShape::PatternFill { x, y, width, height, pattern_type, stroke, stroke_width } => {
                let px = svg.x + x * sx;
                let py = page_height - svg.y - (y + height) * sy;
                let pw = width * sx;
                let ph = height * sy;

                // Draw pattern as inline stream graphics
                stream.extend_from_slice(b"q\n");
                // Clip to region
                write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re W n\n", px, py, pw, ph);

                match pattern_type.as_str() {
                    "diagonal" | "diagonal-lines" => {
                        // Diagonal line pattern
                        stream.extend_from_slice(b"0.8 0.8 0.8 rg\n");
                        write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re f\n", px, py, pw, ph);
                        stream.extend_from_slice(b"0.6 0.6 0.6 RG 0.5 w\n");
                        let step = 8.0;
                        let mut cx = px - ph;
                        while cx < px + pw + ph {
                            write_pdf!(stream, "{:.2} {:.2} m {:.2} {:.2} l S\n", cx, py, cx + ph, py + ph);
                            cx += step;
                        }
                    }
                    "dots" => {
                        // Dot pattern
                        stream.extend_from_slice(b"0.9 0.9 0.9 rg\n");
                        write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re f\n", px, py, pw, ph);
                        stream.extend_from_slice(b"0.5 0.5 0.5 rg\n");
                        let step = 10.0;
                        let dot_r = 1.5;
                        let mut cy = py + step / 2.0;
                        while cy < py + ph {
                            let mut cx = px + step / 2.0;
                            while cx < px + pw {
                                let c = dot_r * 0.552_284_8;
                                write_pdf!(stream,
                                    "{:.2} {:.2} m {:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c {:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c {:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c {:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c f\n",
                                    cx + dot_r, cy,
                                    cx + dot_r, cy + c, cx + c, cy + dot_r, cx, cy + dot_r,
                                    cx - c, cy + dot_r, cx - dot_r, cy + c, cx - dot_r, cy,
                                    cx - dot_r, cy - c, cx - c, cy - dot_r, cx, cy - dot_r,
                                    cx + c, cy - dot_r, cx + dot_r, cy - c, cx + dot_r, cy
                                );
                                cx += step;
                            }
                            cy += step;
                        }
                    }
                    _ => {
                        // Default: crosshatch
                        stream.extend_from_slice(b"0.85 0.85 0.85 rg\n");
                        write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re f\n", px, py, pw, ph);
                        stream.extend_from_slice(b"0.6 0.6 0.6 RG 0.5 w\n");
                        let step = 8.0;
                        // Horizontal lines
                        let mut cy = py;
                        while cy <= py + ph {
                            write_pdf!(stream, "{:.2} {:.2} m {:.2} {:.2} l S\n", px, cy, px + pw, cy);
                            cy += step;
                        }
                        // Vertical lines
                        let mut cx = px;
                        while cx <= px + pw {
                            write_pdf!(stream, "{:.2} {:.2} m {:.2} {:.2} l S\n", cx, py, cx, py + ph);
                            cx += step;
                        }
                    }
                }
                stream.extend_from_slice(b"Q\n");

                // Draw stroke if specified
                if let Some(c) = stroke {
                    svg_stroke_color(&mut stream, c);
                }
                if let Some(w) = stroke_width {
                    write_pdf!(stream, "{:.2} w\n", w * sx);
                }
                if stroke.is_some() {
                    write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re S\n", px, py, pw, ph);
                }
            }
        }
    }
    stream.extend_from_slice(b"Q\n");
    stream
}

fn interpolate_gradient_stops(stops: &[crate::vector::GradientStop], t: f32) -> (f32, f32, f32) {
    if stops.is_empty() {
        return (0.0, 0.0, 0.0);
    }
    if stops.len() == 1 {
        return crate::color::color_to_pdf_rgb(&stops[0].color).unwrap_or((0.0, 0.0, 0.0));
    }

    // Find the two stops that bracket t
    let mut lower = &stops[0];
    let mut upper = &stops[stops.len() - 1];
    for window in stops.windows(2) {
        if t >= window[0].offset && t <= window[1].offset {
            lower = &window[0];
            upper = &window[1];
            break;
        }
    }

    let range = upper.offset - lower.offset;
    let local_t = if range > 0.001 { (t - lower.offset) / range } else { 0.0 };

    let (r1, g1, b1) = crate::color::color_to_pdf_rgb(&lower.color).unwrap_or((0.0, 0.0, 0.0));
    let (r2, g2, b2) = crate::color::color_to_pdf_rgb(&upper.color).unwrap_or((0.0, 0.0, 0.0));

    (
        r1 + (r2 - r1) * local_t,
        g1 + (g2 - g1) * local_t,
        b1 + (b2 - b1) * local_t,
    )
}
