// Axis rendering: draws axes, ticks, labels, titles, and grid lines.

///|
/// Build a font from axis option settings.
fn tickFontFrom(axis : AxisOption, fontFamily : String) -> Font {
  {
    family: fontFamily,
    size: axis.tickFontSize,
    color: axis.tickColor,
    bold: false,
    italic: false,
  }
}

// Build a label font from axis option settings using the given font family.

///|
fn labelFontFrom(axis : AxisOption, fontFamily : String) -> Font {
  {
    family: fontFamily,
    size: axis.labelFontSize,
    color: Color::rgb(0, 0, 0),
    bold: false,
    italic: false,
  }
}

///|
/// Render the Y-axis (left side of plot area). `layout` provides plot and scale geometry; `opt` provides axis styling.
pub fn renderYAxis(layout : Layout, opt : ChartOption) -> String {
  let plot = layout.plot
  let yScale = layout.yScale
  let axis = opt.yAxis
  let axisColorStr = axis.tickColor.toSvg()
  let tickFontVal = tickFontFrom(axis, opt.fontFamily)
  let mut svg = ""

  // Y-axis line (vertical)
  svg = svg +
    line(
      x1=plot.left(),
      y1=plot.top(),
      x2=plot.left(),
      y2=plot.bottom(),
      stroke=axisColorStr,
      strokeWidth=1.0,
    ) +
    "\n"

  // Y-axis ticks
  let tickCount = match axis.tickCount {
    Some(n) => n
    None => 6
  }
  let ticks = yScale.ticks(tickCount)
  let tickLength = 5.0
  for i = 0; i < ticks.length(); i = i + 1 {
    let (pixel, label) = ticks[i]
    let yPos = plot.bottom() - pixel

    // Grid line (horizontal across plot area)
    if axis.gridLine {
      svg = svg +
        line(
          x1=plot.left(),
          y1=yPos,
          x2=plot.right(),
          y2=yPos,
          stroke=axis.gridColor.toSvg(),
          strokeWidth=axis.gridWidth,
        ) +
        "\n"
    }

    // Tick line
    svg = svg +
      line(
        x1=plot.left() - tickLength,
        y1=yPos,
        x2=plot.left(),
        y2=yPos,
        stroke=axisColorStr,
        strokeWidth=1.0,
      ) +
      "\n"
    // Tick label
    svg = svg +
      text(
        x=plot.left() - tickLength - 4.0,
        y=yPos + tickFontVal.size * 0.35,
        content=label,
        font=tickFontVal,
        textAnchor="end",
      ) +
      "\n"
  }

  // Y-axis title
  match axis.label {
    Some(label) => {
      let titleFontVal = labelFontFrom(axis, opt.fontFamily)
      let centerY = plot.centerY()
      let xPos = plot.left() / 2.0 // center of left margin
      svg = svg +
        rotatedText(x=xPos, y=centerY, content=label, font=titleFontVal) +
        "\n"
    }
    None => ()
  }

  svg
}

///|
/// Render the X-axis (bottom of plot area). `layout` provides plot and scale geometry; `opt` provides axis styling.
pub fn renderXAxis(layout : Layout, opt : ChartOption) -> String {
  let plot = layout.plot
  let xScale = layout.xScale
  let axis = opt.xAxis
  let axisColorStr = axis.tickColor.toSvg()
  let tickFontVal = tickFontFrom(axis, opt.fontFamily)
  let mut svg = ""

  // X-axis line (horizontal)
  svg = svg +
    line(
      x1=plot.left(),
      y1=plot.bottom(),
      x2=plot.right(),
      y2=plot.bottom(),
      stroke=axisColorStr,
      strokeWidth=1.0,
    ) +
    "\n"

  // X-axis ticks
  let tickCount = match axis.tickCount {
    Some(n) => n
    None => xScale.count()
  }
  let ticks = xScale.ticks(tickCount)
  let tickLength = 5.0
  for i = 0; i < ticks.length(); i = i + 1 {
    let (pixel, label) = ticks[i]
    let xPos = plot.left() + pixel

    // Grid line (vertical across plot area)
    if axis.gridLine {
      svg = svg +
        line(
          x1=xPos,
          y1=plot.top(),
          x2=xPos,
          y2=plot.bottom(),
          stroke=axis.gridColor.toSvg(),
          strokeWidth=axis.gridWidth,
        ) +
        "\n"
    }

    // Tick line
    svg = svg +
      line(
        x1=xPos,
        y1=plot.bottom(),
        x2=xPos,
        y2=plot.bottom() + tickLength,
        stroke=axisColorStr,
        strokeWidth=1.0,
      ) +
      "\n"
    // Tick label
    svg = svg +
      text(
        x=xPos,
        y=plot.bottom() + tickLength + tickFontVal.size + 2.0,
        content=label,
        font=tickFontVal,
        textAnchor="middle",
      ) +
      "\n"
  }

  // X-axis title
  match axis.label {
    Some(label) => {
      let titleFontVal = labelFontFrom(axis, opt.fontFamily)
      let centerX = plot.centerX()
      let yPos = plot.bottom() +
        tickLength +
        tickFontVal.size +
        titleFontVal.size +
        6.0
      svg = svg +
        text(
          x=centerX,
          y=yPos,
          content=label,
          font=titleFontVal,
          textAnchor="middle",
        ) +
        "\n"
    }
    None => ()
  }

  svg
}

///|
/// Render the chart title (centered at top). `opt` provides the title text and chart dimensions.
pub fn renderTitle(opt : ChartOption) -> String {
  match opt.title {
    Some(title) => {
      let fontVal = titleFont()
      let centerX = opt.width / 2.0
      let yPos = opt.margin.top / 2.0 + fontVal.size * 0.35
      text(x=centerX, y=yPos, content=title, font=fontVal, textAnchor="middle")
    }
    None => ""
  }
}