use std::io::Write;
#[cfg(feature = "svg")]
#[allow(unused_imports)]
use super::svg;
use super::utils::{write_pdf, pdf_fill_color, pdf_stroke_color};

pub fn render_circle(cx: f32, cy: f32, r: f32) -> Vec<u8> {
    let c = r * 0.552_284_8;
    let mut buf = Vec::with_capacity(128);
    write_pdf!(buf,
        "{:.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 + r, cy,
        cx + r, cy + c, cx + c, cy + r, cx, cy + r,
        cx - c, cy + r, cx - r, cy + c, cx - r, cy,
        cx - r, cy - c, cx - c, cy - r, cx, cy - r,
        cx + c, cy - r, cx + r, cy - c, cx + r, cy
    );
    buf
}

pub fn render_circle_stroke(cx: f32, cy: f32, r: f32) -> Vec<u8> {
    let c = r * 0.552_284_8;
    let stroke_width = r * 0.2;
    let mut buf = Vec::with_capacity(128);
    write_pdf!(buf, "{:.2} w\n", stroke_width);
    write_pdf!(buf,
        "{:.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 S\n",
        cx + r, cy,
        cx + r, cy + c, cx + c, cy + r, cx, cy + r,
        cx - c, cy + r, cx - r, cy + c, cx - r, cy,
        cx - r, cy - c, cx - c, cy - r, cx, cy - r,
        cx + c, cy - r, cx + r, cy - c, cx + r, cy
    );
    buf
}

pub fn render_square_marker(x: f32, cy: f32, size: f32) -> Vec<u8> {
    let mut buf = Vec::with_capacity(64);
    let half = size * 0.5;
    write_pdf!(buf, "{:.2} {:.2} {:.2} {:.2} re f\n", x - half, cy - half, size, size);
    buf
}

pub fn build_rect_ops(
    x: f32, y: f32, w: f32, h: f32,
    color: Option<&str>,
    line_color: Option<&str>,
    line_width: Option<f32>,
    fill_opacity: Option<f32>,
    stroke_opacity: Option<f32>,
) -> Vec<u8> {
    let mut stream = Vec::with_capacity(128);
    stream.extend_from_slice(b"q\n");

    if let Some(op) = fill_opacity {
        if op < 1.0 {
            let pct = (op * 100.0).round() as u8;
            write_pdf!(stream, "/gs{} gs ", pct);
        }
    }
    if let Some(op) = stroke_opacity {
        if op < 1.0 {
            let pct = (op * 100.0).round() as u8;
            write_pdf!(stream, "/gs{} gs ", pct);
        }
    }

    if let Some(c) = color {
        pdf_fill_color(&mut stream, c);
    }
    if let Some(c) = line_color {
        pdf_stroke_color(&mut stream, c);
    }
    if let Some(w) = line_width {
        write_pdf!(stream, "{:.2} w\n", w);
    }

    write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} re\n", x, y, w, h);

    let has_fill = color.is_some();
    let has_stroke = line_color.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"),
    }

    stream.extend_from_slice(b"Q\n");
    stream
}

pub fn build_ellipse_ops(
    x: f32, y: f32, r1: f32, r2: f32,
    color: Option<&str>,
    line_color: Option<&str>,
    line_width: Option<f32>,
) -> Vec<u8> {
    let mut stream = Vec::with_capacity(256);
    stream.extend_from_slice(b"q\n");

    if let Some(c) = color {
        pdf_fill_color(&mut stream, c);
    }
    if let Some(c) = line_color {
        pdf_stroke_color(&mut stream, c);
    }
    if let Some(w) = line_width {
        write_pdf!(stream, "{:.2} w\n", w);
    }

    let cx = x;
    let cy = y;
    let k = 0.552_284_8;
    let kx = r1 * k;
    let ky = r2 * k;

    write_pdf!(stream, "{:.2} {:.2} m\n", cx + r1, cy);
    write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", cx + r1, cy + ky, cx + kx, cy + r2, cx, cy + r2);
    write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", cx - kx, cy + r2, cx - r1, cy + ky, cx - r1, cy);
    write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", cx - r1, cy - ky, cx - kx, cy - r2, cx, cy - r2);
    write_pdf!(stream, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n", cx + kx, cy - r2, cx + r1, cy - ky, cx + r1, cy);

    let has_fill = color.is_some();
    let has_stroke = line_color.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"),
    }

    stream.extend_from_slice(b"Q\n");
    stream
}

pub fn build_line_ops(
    x1: f32, y1: f32, x2: f32, y2: f32,
    line_color: Option<&str>,
    line_width: Option<f32>,
) -> Vec<u8> {
    let mut stream = Vec::with_capacity(64);
    stream.extend_from_slice(b"q\n");

    if let Some(c) = line_color {
        pdf_stroke_color(&mut stream, c);
    }
    if let Some(w) = line_width {
        write_pdf!(stream, "{:.2} w\n", w);
    }

    write_pdf!(stream, "{:.2} {:.2} m {:.2} {:.2} l S\n", x1, y1, x2, y2);

    stream.extend_from_slice(b"Q\n");
    stream
}

#[allow(dead_code)]
pub fn build_polyline_ops(
    points: &[crate::model::CanvasPoint],
    close_path: bool,
    color: Option<&str>,
    line_color: Option<&str>,
    line_width: Option<f32>,
    page_height: f32,
) -> Vec<u8> {
    let mut stream = Vec::with_capacity(256);
    if points.is_empty() {
        return stream;
    }

    stream.extend_from_slice(b"q\n");

    if let Some(c) = color {
        pdf_fill_color(&mut stream, c);
    }
    if let Some(c) = line_color {
        pdf_stroke_color(&mut stream, c);
    }
    if let Some(w) = line_width {
        write_pdf!(stream, "{:.2} w\n", w);
    }

    let first = &points[0];
    write_pdf!(stream, "{:.2} {:.2} m\n", first.x, page_height - first.y);

    for p in &points[1..] {
        write_pdf!(stream, "{:.2} {:.2} l\n", p.x, page_height - p.y);
    }

    if close_path {
        stream.extend_from_slice(b"h\n");
    }

    let has_fill = color.is_some();
    let has_stroke = line_color.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"),
    }

    stream.extend_from_slice(b"Q\n");
    stream
}

pub fn build_polyline_ops_offset(
    points: &[crate::model::CanvasPoint],
    close_path: bool,
    color: Option<&str>,
    line_color: Option<&str>,
    line_width: Option<f32>,
    page_height: f32,
    offset_x: f32,
    offset_y: f32,
) -> Vec<u8> {
    let mut stream = Vec::with_capacity(256);
    if points.is_empty() {
        return stream;
    }

    stream.extend_from_slice(b"q\n");

    if let Some(c) = color {
        pdf_fill_color(&mut stream, c);
    }
    if let Some(c) = line_color {
        pdf_stroke_color(&mut stream, c);
    }
    if let Some(w) = line_width {
        write_pdf!(stream, "{:.2} w\n", w);
    }

    let first = &points[0];
    write_pdf!(stream, "{:.2} {:.2} m\n", offset_x + first.x, page_height - offset_y - first.y);

    for p in &points[1..] {
        write_pdf!(stream, "{:.2} {:.2} l\n", offset_x + p.x, page_height - offset_y - p.y);
    }

    if close_path {
        stream.extend_from_slice(b"h\n");
    }

    let has_fill = color.is_some();
    let has_stroke = line_color.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"),
    }

    stream.extend_from_slice(b"Q\n");
    stream
}
