# test/growth/score/weight_for_height_test.exs
defmodule Growth.Score.WeightForHeightTest do
  use ExUnit.Case, async: true

  alias Growth
  alias Growth.Score.WeightForHeight

  describe "measure_name/0" do
    test "returns the correct measure name atom" do
      assert WeightForHeight.measure_name() == :weight_for_height
    end
  end

  describe "lms/2" do
    test "returns LMS values for exact height match" do
      growth = %Growth{
        gender: :male,
        weight: 7.3,
        height: 65.0,
        name: "Joe Doe",
        date_of_measurement: Date.utc_today(),
        date_of_birth: Date.shift(Date.utc_today(), day: -91)
      }

      assert WeightForHeight.lms(growth, WeightForHeight) == [
               {"height", {-0.35210000000000002, 7.4326999999999996, 0.082170000000000007}}
             ]
    end

    test "returns LMS values for closest height match when exact is not found" do
      growth = %Growth{
        gender: :male,
        weight: 7.3,
        height: 64.9,
        name: "Joe Doe",
        date_of_measurement: Date.utc_today(),
        date_of_birth: Date.shift(Date.utc_today(), day: -91)
      }

      assert WeightForHeight.lms(growth, WeightForHeight) == [
               {"height", {-0.35210000000000002, 7.4326999999999996, 0.082170000000000007}}
             ]

      growth_closer_to_higher = %Growth{
        gender: :male,
        weight: 7.4,
        height: 65.09,
        name: "Joe Doe",
        date_of_measurement: Date.utc_today(),
        date_of_birth: Date.shift(Date.utc_today(), day: -91)
      }

      assert WeightForHeight.lms(growth_closer_to_higher, WeightForHeight) == [
               {"height", {-0.35210000000000002, 7.4562999999999997, 0.082159999999999997}}
             ]
    end

    test "returns empty list if weight or height is missing" do
      growth_no_weight = %Growth{
        gender: :male,
        height: 60.0,
        name: "Joe Doe",
        date_of_measurement: Date.utc_today(),
        date_of_birth: Date.shift(Date.utc_today(), day: -91)
      }

      assert WeightForHeight.lms(growth_no_weight, WeightForHeight) == []

      growth_no_height = %Growth{
        gender: :male,
        weight: 5.0,
        name: "Joe Doe",
        date_of_measurement: Date.utc_today(),
        date_of_birth: Date.shift(Date.utc_today(), day: -91)
      }

      assert WeightForHeight.lms(growth_no_height, WeightForHeight) == []

      growth_nil_values = %Growth{
        gender: :male,
        weight: nil,
        height: nil,
        name: "Joe Doe",
        date_of_measurement: Date.utc_today(),
        date_of_birth: Date.shift(Date.utc_today(), day: -91)
      }

      assert WeightForHeight.lms(growth_nil_values, WeightForHeight) == []
    end

    test "returns empty list if no matching gender data exists" do
      # Assuming no :unknown gender data was inserted
      growth = %Growth{
        gender: :unknown,
        weight: 5.0,
        height: 60.0,
        name: "Joe Doe",
        date_of_measurement: Date.utc_today(),
        date_of_birth: Date.shift(Date.utc_today(), day: -91)
      }

      assert WeightForHeight.lms(growth, WeightForHeight) == []
    end
  end

  describe "find_closest_height/2" do
    test "finds the lower closest height" do
      assert WeightForHeight.find_closest_height(:male, 64.99) == [
               {"height", {-0.35210000000000002, 7.4326999999999996, 0.082170000000000007}}
             ]
    end

    test "finds the higher closest height" do
      assert WeightForHeight.find_closest_height(:male, 65.61) == [
               {"height", {-0.35210000000000002, 7.5738000000000003, 0.082140000000000005}}
             ]
    end

    test "finds the lower closest height when exactly midway" do
      expected_lms =
        [
          [{"height", {-0.35210000000000002, 7.5034000000000001, 0.082150000000000001}}],
          [{"height", {-0.35210000000000002, 7.4798999999999998, 0.082159999999999997}}]
        ]

      lms = WeightForHeight.find_closest_height(:male, 65.25)
      assert Enum.any?(expected_lms, fn entity_lms -> entity_lms == lms end)
    end

    test "do not match when below minimum height" do
      assert WeightForHeight.find_closest_height(:male, 44.0) == []
    end

    test "do not match when above maximum height" do
      assert WeightForHeight.find_closest_height(:male, 121.0) == []
    end

    test "returns empty list when no data exists for the gender" do
      assert WeightForHeight.find_closest_height(:unknown, 60.0) == []
    end
  end
end
