defmodule MicrowavepropWeb.SkewtSvgTest do
  use ExUnit.Case, async: true

  alias MicrowavepropWeb.SkewtSvg

  @profile [
    %{"pres" => 1013.0, "hght" => 100.0, "tmpc" => 25.0, "dwpc" => 18.0},
    %{"pres" => 925.0, "hght" => 800.0, "tmpc" => 18.0, "dwpc" => 14.0},
    %{"pres" => 850.0, "hght" => 1500.0, "tmpc" => 12.0, "dwpc" => 9.0},
    %{"pres" => 700.0, "hght" => 3000.0, "tmpc" => 0.0, "dwpc" => -5.0},
    %{"pres" => 500.0, "hght" => 5500.0, "tmpc" => -15.0, "dwpc" => -25.0},
    %{"pres" => 300.0, "hght" => 9000.0, "tmpc" => -45.0, "dwpc" => -65.0}
  ]

  describe "render/1" do
    test "produces a valid <svg> root with the expected viewBox" do
      svg = @profile |> SkewtSvg.render() |> IO.iodata_to_binary()

      assert svg =~ ~r|<svg[^>]*viewBox="0 0 820 640"|
      assert String.ends_with?(svg, "</svg>")
    end

    test "draws temperature and dewpoint polylines" do
      svg = @profile |> SkewtSvg.render() |> IO.iodata_to_binary()

      assert svg =~ ~s|class="temp-line"|
      assert svg =~ ~s|class="dew-line"|
    end

    test "tolerates Rust-style atom-keyed levels" do
      rust_profile = [
        %{pres_mb: 1013.0, hght_m: 100.0, tmpc: 25.0, dwpc: 18.0},
        %{pres_mb: 850.0, hght_m: 1500.0, tmpc: 12.0, dwpc: 9.0},
        %{pres_mb: 500.0, hght_m: 5500.0, tmpc: -15.0, dwpc: -25.0}
      ]

      svg = rust_profile |> SkewtSvg.render() |> IO.iodata_to_binary()
      assert svg =~ ~s|class="temp-line"|
    end

    test "renders without trace polylines on an empty profile" do
      svg = [] |> SkewtSvg.render() |> IO.iodata_to_binary()

      # The style block always defines the trace classes; only the
      # polyline elements should be missing for an empty profile.
      assert svg =~ "<svg"
      refute svg =~ ~s|<polyline class="temp-line"|
      refute svg =~ ~s|<polyline class="dew-line"|
    end

    test "skips levels missing the dewpoint" do
      partial = [
        %{"pres" => 1000.0, "hght" => 100.0, "tmpc" => 20.0, "dwpc" => 10.0},
        %{"pres" => 500.0, "hght" => 5000.0, "tmpc" => -10.0, "dwpc" => nil}
      ]

      svg = partial |> SkewtSvg.render() |> IO.iodata_to_binary()
      # Temperature line must still draw both points.
      assert svg =~ ~s|class="temp-line"|
      # Dewpoint line will only contain the bottom point and renders as
      # nothing (single-point polyline) — that's fine, the test asserts
      # the renderer didn't crash.
      assert svg =~ "</svg>"
    end
  end

  describe "coordinate transforms" do
    test "pressure_y is monotonically decreasing as pressure decreases" do
      y1000 = SkewtSvg.pressure_y(1000)
      y500 = SkewtSvg.pressure_y(500)
      y100 = SkewtSvg.pressure_y(100)

      assert y1000 > y500
      assert y500 > y100
    end

    test "temperature_x at the bottom edge: warmer = further right" do
      cold = SkewtSvg.temperature_x(-20, SkewtSvg.pressure_y(1000))
      warm = SkewtSvg.temperature_x(20, SkewtSvg.pressure_y(1000))
      assert warm > cold
    end

    test "temperature_x is skewed: same temperature shifts right as pressure decreases" do
      bottom = SkewtSvg.temperature_x(0, SkewtSvg.pressure_y(1000))
      top = SkewtSvg.temperature_x(0, SkewtSvg.pressure_y(300))
      # Skew-T isotherms lean lower-left → upper-right, so the same
      # 0 °C plotted at 300 mb sits to the right of 0 °C at 1000 mb.
      assert top > bottom
    end
  end
end
