defmodule Aprsme.Passcode do
  @moduledoc """
  Module for generating APRS passcodes from callsigns.
  The passcode is a hash of the callsign used for authentication with APRS-IS servers.
  """

  @doc """
  Generates an APRS passcode for a given callsign.

  ## Parameters
    - callsign: The amateur radio callsign (e.g., "W5ISP")

  ## Returns
    - The generated passcode as an integer

  ## Examples
      iex> Aprsme.Passcode.generate("W5ISP")
      15748
  """
  @spec generate(String.t()) :: non_neg_integer()
  def generate(callsign) when is_binary(callsign) do
    # Split on '-' and take first part, uppercase, and limit to 10 chars
    realcall =
      callsign
      |> String.split("-")
      |> List.first()
      |> String.upcase()
      |> String.slice(0, 10)

    # Convert string to charlist for easier processing
    chars = String.to_charlist(realcall)

    # Initial hash value
    hash = 0x73E2

    # Process characters in pairs, incrementing by 2 each time
    hash =
      Enum.reduce(0..div(length(chars) - 1, 2), hash, fn i, acc ->
        current_char = Enum.at(chars, i * 2)
        next_char = if i * 2 + 1 < length(chars), do: Enum.at(chars, i * 2 + 1)
        step1 = Bitwise.bxor(acc, Bitwise.bsl(current_char, 8))

        step2 =
          if next_char do
            Bitwise.bxor(step1, next_char)
          else
            step1
          end

        step2
      end)

    # Return final hash masked to 15 bits
    Bitwise.band(hash, 0x7FFF)
  end
end
