///|
fn pdf_addtext_degrees_to_radians(degrees : Double) -> Double {
  degrees * @math.PI / 180.0
}

///|
/// Convert cpdf add-text's explicit rotation enum to content rotation radians.
pub fn pdf_addtext_rotation_radians(rotation : PdfAddTextRotation) -> Double {
  match rotation {
    PdfAddTextRot0 => 0.0
    PdfAddTextRot90 => pdf_addtext_degrees_to_radians(270.0)
    PdfAddTextRot180 => pdf_addtext_degrees_to_radians(180.0)
    PdfAddTextRot270 => pdf_addtext_degrees_to_radians(90.0)
  }
}

///|
/// Return cpdf's rotation-dependent text origin offset.
pub fn pdf_addtext_rotation_offsets(
  position : @geometry.PdfPosition,
  rotation : PdfAddTextRotation,
  text_width : Double,
) -> (Double, Double) {
  match position {
    PdfPositionTopLeft(_, _) =>
      match rotation {
        PdfAddTextRot0 | PdfAddTextRot90 => (0.0, 0.0)
        PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (0.0, -text_width)
      }
    PdfPositionTop(_) =>
      match rotation {
        PdfAddTextRot0 => (0.0, 0.0)
        PdfAddTextRot90 => (text_width / 2.0, 0.0)
        PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (text_width / 2.0, -text_width)
      }
    PdfPositionTopRight(_, _) =>
      match rotation {
        PdfAddTextRot0 => (0.0, 0.0)
        PdfAddTextRot90 | PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (text_width, -text_width)
      }
    PdfPositionRight(_) | PdfPositionPosRight(_, _) =>
      match rotation {
        PdfAddTextRot0 => (0.0, 0.0)
        PdfAddTextRot90 => (text_width, text_width / 2.0)
        PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (text_width, -text_width / 2.0)
      }
    PdfPositionBottomRight(_, _) =>
      match rotation {
        PdfAddTextRot0 => (0.0, 0.0)
        PdfAddTextRot90 => (text_width, text_width)
        PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (text_width, 0.0)
      }
    PdfPositionBottom(_) =>
      match rotation {
        PdfAddTextRot0 => (0.0, 0.0)
        PdfAddTextRot90 => (text_width / 2.0, text_width)
        PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (text_width / 2.0, 0.0)
      }
    PdfPositionBottomLeft(_, _) =>
      match rotation {
        PdfAddTextRot0 => (0.0, 0.0)
        PdfAddTextRot90 => (0.0, text_width)
        PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (0.0, 0.0)
      }
    PdfPositionLeft(_) | PdfPositionPosLeft(_, _) =>
      match rotation {
        PdfAddTextRot0 => (0.0, 0.0)
        PdfAddTextRot90 => (0.0, text_width / 2.0)
        PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (0.0, -text_width / 2.0)
      }
    PdfPositionCentre | PdfPositionPosCentre(_, _) =>
      match rotation {
        PdfAddTextRot0 => (0.0, 0.0)
        PdfAddTextRot90 => (text_width / 2.0, text_width / 2.0)
        PdfAddTextRot180 => (text_width, 0.0)
        PdfAddTextRot270 => (text_width / 2.0, -(text_width / 2.0))
      }
    PdfPositionDiagonal | PdfPositionReverseDiagonal => (0.0, 0.0)
  }
}

///|
/// Adjust cpdf add-text offsets for diagonal and reverse-diagonal placement.
pub fn pdf_addtext_diagonal_offsets(
  bounds : @geometry.PdfRectangle,
  position : @geometry.PdfPosition,
  rotation : PdfAddTextRotation,
  text_width : Double,
  horizontal_offset : Double,
  vertical_offset : Double,
  base_rotation : Double,
) -> (Double, Double) {
  match position {
    PdfPositionDiagonal | PdfPositionReverseDiagonal => {
      let rotate = if rotation == PdfAddTextRot180 {
        base_rotation + @math.PI
      } else {
        base_rotation
      }
      let horizontal = -(@math.cos(@math.PI / 2.0 - rotate) * vertical_offset)
      let vertical = @math.sin(@math.PI / 2.0 - rotate) * vertical_offset
      if rotation == PdfAddTextRot180 {
        let angle = @math.atan(
          (bounds.max_y - bounds.min_y) / (bounds.max_x - bounds.min_x),
        )
        let dx = @math.cos(angle) * text_width
        let dy = @math.sin(angle) * text_width
        match position {
          PdfPositionDiagonal => (horizontal - dx, vertical - dy)
          PdfPositionReverseDiagonal => (horizontal - dx, vertical + dy)
          _ => (horizontal, vertical)
        }
      } else {
        (horizontal, vertical)
      }
    }
    _ => (horizontal_offset, vertical_offset)
  }
}

///|
/// Return cpdf's initial `(horizontal, vertical)` offset for a multi-line
/// add-text paragraph.
pub fn pdf_addtext_initial_line_offsets(
  position : @geometry.PdfPosition,
  line_count : Int,
  line_spacing : Double,
  font_size : Double,
) -> (Double, Double) {
  let line_delta = (line_count - 1).to_double()
  let paragraph_height = line_spacing * font_size * line_delta
  let vertical = match position {
    PdfPositionBottomLeft(_, _)
    | PdfPositionBottom(_)
    | PdfPositionBottomRight(_, _) => -paragraph_height
    PdfPositionLeft(_) | PdfPositionRight(_) => -(paragraph_height / 2.0)
    PdfPositionDiagonal | PdfPositionReverseDiagonal =>
      -(paragraph_height / 2.0)
    _ => 0.0
  }
  (0.0, vertical)
}

///|
/// Return cpdf's per-line `(horizontal, vertical)` advance for add-text.
pub fn pdf_addtext_line_advance(
  rotation : PdfAddTextRotation,
  line_spacing : Double,
  font_size : Double,
) -> (Double, Double) {
  let advance = line_spacing * font_size
  match rotation {
    PdfAddTextRot90 | PdfAddTextRot270 => (advance, 0.0)
    PdfAddTextRot0 | PdfAddTextRot180 => (0.0, advance)
  }
}