# Localize.PhoneNumber

Elixir interface to Google's [libphonenumber](https://github.com/google/libphonenumber) C++ library via NIF. Provides phone number parsing, formatting, validation, type detection, and territory resolution with locale-aware defaults powered by [Localize](https://hexdocs.pm/localize).

## Usage

Parse a phone number in international format:

```elixir
iex> {:ok, phone_number} = Localize.PhoneNumber.parse("+1 650-253-0000")
iex> phone_number.country_code
1
iex> phone_number.national_number
6502530000
```

Parse a national number by supplying a territory or locale:

```elixir
iex> {:ok, phone_number} = Localize.PhoneNumber.parse("020 7946 0958", territory: "GB")
iex> phone_number.country_code
44

iex> {:ok, phone_number} = Localize.PhoneNumber.parse("020 7946 0958", locale: "en-GB")
iex> phone_number.country_code
44
```

When neither `:territory` nor `:locale` is given, the default territory is derived from `Localize.get_locale/0`.

Format a parsed number:

```elixir
iex> {:ok, phone_number} = Localize.PhoneNumber.parse("+1 650-253-0000")
iex> Localize.PhoneNumber.to_string(phone_number, :e164)
{:ok, "+16502530000"}

iex> Localize.PhoneNumber.to_string(phone_number, :international)
{:ok, "+1 650-253-0000"}

iex> Localize.PhoneNumber.to_string(phone_number, :national)
{:ok, "(650) 253-0000"}

iex> Localize.PhoneNumber.to_string(phone_number, :rfc3966)
{:ok, "tel:+1-650-253-0000"}
```

Validate a number:

```elixir
iex> {:ok, phone_number} = Localize.PhoneNumber.parse("+1 650-253-0000")
iex> Localize.PhoneNumber.valid?(phone_number)
true

iex> Localize.PhoneNumber.valid_for_territory?(phone_number, "US")
true

iex> Localize.PhoneNumber.possible?(phone_number)
true
```

Detect the number type and territory:

```elixir
iex> {:ok, phone_number} = Localize.PhoneNumber.parse("+1 800-555-0199")
iex> Localize.PhoneNumber.type(phone_number)
:toll_free

iex> Localize.PhoneNumber.territory(phone_number)
"US"
```

See the [Parsing and Formatting Guide](https://hexdocs.pm/localize_phone_number/parsing_and_formatting.html) for detailed usage examples.

## API Summary

| Function | Description |
|----------|-------------|
| `parse/2` | Parse a phone number string into a struct. |
| `to_string/2` | Format a parsed number (`:e164`, `:international`, `:national`, `:rfc3966`). Default is `:international`. |
| `valid?/1` | Check if a parsed number is valid. |
| `valid_for_territory?/2` | Check if a parsed number is valid for a specific territory. |
| `possible?/1` | Quick check if a number has a plausible length. |
| `type/1` | Detect the number type (`:mobile`, `:fixed_line`, `:toll_free`, etc.). |
| `territory/1` | Get the ISO 3166-1 alpha-2 territory code for a number. |

## Territory Resolution

The `parse/2` function needs a default territory to interpret national-format numbers. The territory is resolved in priority order:

1. Explicit `:territory` option — validated via `Localize.validate_territory/1`.
2. Extracted from the `:locale` option — resolved via `Localize.Territory.territory_from_locale/1`. Accepts a string (`"en-GB"`), atom (`:en_GB`), or `Localize.LanguageTag.t()` struct.
3. Derived from the current process locale via `Localize.get_locale/0`.

## Prerequisites

### System Libraries

Google's libphonenumber C++ library must be installed on the build machine. The NIF is compiled automatically by `elixir_make` during `mix compile`.

**macOS (Homebrew):**

```bash
brew install libphonenumber
```

This installs libphonenumber along with its transitive dependencies (protobuf, abseil, boost, and ICU). The Makefile detects the Homebrew prefix automatically on both Apple Silicon (`/opt/homebrew`) and Intel (`/usr/local`) Macs.

**Linux (Debian/Ubuntu):**

```bash
sudo apt-get install libphonenumber-dev libprotobuf-dev protobuf-compiler
```

On distributions that provide a `pkg-config` file for libphonenumber, the Makefile uses it automatically. Otherwise it falls back to standard system library paths.

**Linux (Fedora/RHEL):**

```bash
sudo dnf install libphonenumber-devel protobuf-devel
```

**From source:**

If your distribution does not package libphonenumber, build it from [source](https://github.com/google/libphonenumber/blob/master/cpp/README). Ensure the headers are installed to a standard include path and the shared library is on the linker search path.

### Elixir Dependencies

Add `localize_phone_number` to your `mix.exs`:

```elixir
def deps do
  [
    {:localize_phone_number, "~> 0.1.0"}
  ]
end
```

The library depends on:

* [`localize`](https://hexdocs.pm/localize) — locale and territory resolution.
* [`elixir_make`](https://hex.pm/packages/elixir_make) — compiles the C++ NIF during `mix compile`.

## Architecture

### NIF Design

The library is a thin Elixir wrapper around a C++ NIF that calls libphonenumber's `PhoneNumberUtil` singleton directly. The NIF is compiled automatically by `elixir_make` during `mix compile`.

```
Localize.PhoneNumber              Public API (parse, to_string, valid?, type, territory)
    │
    ├── Localize.PhoneNumber.Territory   Locale-to-territory resolution via Localize
    │
    └── Localize.PhoneNumber.Nif         NIF loader and Elixir stubs
         │
         └── localize_phone_number_nif.cpp
              │
              └── libphonenumber (PhoneNumberUtil)
```

### Parsed Phone Number Struct

`Localize.PhoneNumber.parse/2` returns a `Localize.PhoneNumber.Number` struct:

```elixir
%Localize.PhoneNumber.Number{
  country_code: 1,
  national_number: 6502530000,
  extension: nil,
  raw_input: "+1 650-253-0000"
}
```

The struct also carries an opaque `__native__` field containing the serialized protobuf representation of the phone number. This binary is passed back to the NIF for all subsequent operations (`to_string/2`, `valid?/1`, `type/1`, etc.), ensuring lossless round-trips that preserve metadata such as Italian leading zeros and preferred formatting hints. The `__native__` field is excluded from `Inspect` output.

### Thread Safety

`PhoneNumberUtil::GetInstance()` returns a process-global singleton that is thread-safe for all read operations. No pooling or mutexes are needed — every NIF call can run concurrently on any BEAM scheduler.

### Build System

The `c_src/Makefile` follows the same pattern used by the `localize` project:

* Generates `env.mk` at build time to discover ERTS include paths.
* Detects the platform (macOS ARM/x86, Linux, FreeBSD) and sets appropriate compiler flags.
* Finds libphonenumber, protobuf, and abseil via `pkg-config` with Homebrew fallback paths on macOS.
* Compiles C++17 with `-O3 -fPIC` and produces a shared library at `priv/localize_phone_number_nif.so`.

## License

[Apache-2.0](https://github.com/elixir-localize/localize_phone_number/blob/v0.1.0/LICENSE.md)
