defmodule Microwaveprop.Qrz.RecordTest do
  use ExUnit.Case, async: true

  alias Microwaveprop.Qrz.Record

  describe "from_map/1" do
    test "returns a struct with all fields nil for an empty map" do
      assert %Record{
               call: nil,
               fname: nil,
               name: nil,
               grid: nil,
               addr1: nil,
               addr2: nil,
               state: nil,
               zip: nil,
               country: nil,
               lat: nil,
               lon: nil
             } = Record.from_map(%{})
    end

    test "parses every known string field" do
      data = %{
        "call" => "W1AW",
        "fname" => "Hiram Percy",
        "name" => "Maxim",
        "grid" => "FN31pr",
        "addr1" => "225 Main St",
        "addr2" => "Newington",
        "state" => "CT",
        "zip" => "06111",
        "country" => "United States"
      }

      record = Record.from_map(data)

      assert record.call == "W1AW"
      assert record.fname == "Hiram Percy"
      assert record.name == "Maxim"
      assert record.grid == "FN31pr"
      assert record.addr1 == "225 Main St"
      assert record.addr2 == "Newington"
      assert record.state == "CT"
      assert record.zip == "06111"
      assert record.country == "United States"
    end

    test "parses lat and lon as floats from numeric strings" do
      record = Record.from_map(%{"lat" => "41.714775", "lon" => "-72.727260"})

      assert record.lat == 41.714775
      assert record.lon == -72.727260
    end

    test "parses partial float prefixes via Float.parse/1" do
      # Float.parse/1 returns {41.714, "abc"} — the parser keeps the float.
      assert %Record{lat: 41.714} = Record.from_map(%{"lat" => "41.714abc"})
    end

    test "returns nil for unparseable float strings" do
      assert %Record{lat: nil} = Record.from_map(%{"lat" => "not-a-number"})
    end

    test "treats non-binary string values as nil" do
      assert %Record{call: nil} = Record.from_map(%{"call" => 123})
    end

    test "treats non-binary lat/lon values as nil" do
      # The parser only accepts binaries — a raw float is rejected.
      assert %Record{lat: nil, lon: nil} = Record.from_map(%{"lat" => 41.714, "lon" => -72.727})
    end

    test "leaves a field as nil when the key is absent" do
      assert %Record{call: "W1AW", fname: nil} = Record.from_map(%{"call" => "W1AW"})
    end

    test "treats an explicit nil value the same as a missing key" do
      assert %Record{call: nil} = Record.from_map(%{"call" => nil})
    end

    test "ignores unknown XML keys" do
      record = Record.from_map(%{"call" => "W1AW", "eqsl" => "1", "dxcc" => "291"})

      assert record.call == "W1AW"
      # No crash, no struct pollution.
      assert record |> Map.from_struct() |> Map.keys() |> Enum.sort() ==
               [:addr1, :addr2, :call, :country, :fname, :grid, :lat, :lon, :name, :state, :zip]
    end

    test "is JSON-encodable via Jason" do
      record = Record.from_map(%{"call" => "W1AW", "lat" => "41.714"})
      json = Jason.encode!(record)
      decoded = Jason.decode!(json)

      assert decoded["call"] == "W1AW"
      assert decoded["lat"] == 41.714
    end
  end
end
