///|
fn response_color(response : @evidence.TargetResponse) -> String {
  match response {
    CR => "#6f4fa0"
    PR => "#247b68"
    SD => "#34748a"
    PD => "#b5473e"
    NE => "#787b83"
  }
}

///|
/// Self-contained SVG: target sum, baseline and baseline-minus-30% guides.
/// NE visits break the line and are never plotted as a zero-diameter result.
pub fn render_trajectory_svg(trajectory : @evidence.Trajectory) -> String {
  render_trajectory_svg_in(trajectory, English)
}

///|
/// Localized presentation; input-derived text and machine codes are preserved.
pub fn render_trajectory_svg_in(
  trajectory : @evidence.Trajectory,
  language : ReportLanguage,
) -> String {
  let mut baseline = 0
  for target in trajectory.study.targets {
    baseline += target.baseline_tenths_mm
  }
  let mut maximum = baseline
  for a in trajectory.assessments {
    if a.sum_tenths_mm is Some(sum) && sum > maximum {
      maximum = sum
    }
  }
  maximum = maximum * 5 / 4 + 1
  let y = (value : Int) => 30 + (maximum - value) * 210 / maximum
  let out = StringBuilder()
  out.write_string(
    tr(
      language, "Target diameter sumsBaseline and ordered follow-up target sums. Not-evaluable visits break the line. The dashed lower guide is a 30 percent baseline reduction, not an overall-response threshold.",
      "靶病灶直径总和基线与有序随访的靶病灶总和。NE 随访断线。下方虚线表示基线减少 30%,不代表整体疗效阈值。",
    ),
  )
  for
    (value, label, color) in [
      (baseline, tr(language, "Baseline", "基线"), "#7c8390"),
      (
        baseline * 7 / 10,
        tr(language, "Baseline -30%", "基线 -30%"),
        "#b1b7ba",
      ),
    ] {
    out.write_string(
      "\{label}: \{format_diameter_mm(value)} mm",
    )
  }
  out.write_string(
    tr(
      language,
      "mmBaseline",
      "mm基线",
    ),
  )
  let mut previous : (Int, Int)? = Some((70, y(baseline)))
  for i, a in trajectory.assessments {
    let x = 70 + (i + 1) * 840 / (trajectory.assessments.length() + 1)
    let color = response_color(a.response)
    if a.response != NE && a.sum_tenths_mm is Some(sum) {
      let py = y(sum)
      if previous is Some((px, previous_y)) {
        out.write_string(
          "",
        )
      }
      out.write_string(
        "" +
        html_escape(a.visit_id) +
        ": " +
        format_diameter_mm(sum) +
        " mm / " +
        a.response.code() +
        "",
      )
      previous = Some((x, py))
    } else {
      out.write_string(
        "" +
        html_escape(a.visit_id) +
        tr(
          language, ": NE; excluded from trend line", ": NE;不进入总和趋势线",
        ),
      )
      previous = None
    }
    out.write_string(
      "V\{i + 1}" +
      a.response.code() +
      "",
    )
  }
  out.write_string("\n")
  out.to_string()
}