import {Meta} from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/functional/en/Classes/GeoPhone'/>

# GeoPhone Class

A static class for storing and processing phone number masks. Provides methods for working with international phone codes, formatting numbers according to masks, and identifying countries by phone numbers.

## Key Features

- **International phone codes** — support for all international country codes
- **Phone masks** — automatic number formatting according to national standards
- **Country detection by number** — identifying country based on phone number
- **Tree structure for codes** — efficient search and number matching
- **Internal country codes** — support for special symbols for national numbers
- **Number validation** — verification of phone number correctness
- **Static methods** — all operations available without creating an instance

## Static Methods

### `get`

Gets an object with information about the phone code and country.

**Parameters:**
- `code: string` — country and language code

**Returns:** `GeoPhoneValue | undefined` — object with phone code information or undefined

```javascript
import { GeoPhone } from '@dxtmisha/functional'

// Get information about Russia
const russiaPhone = GeoPhone.get('RU')
console.log(russiaPhone)
// {
//   phone: 7,           // international code
//   within: 8,          // internal code
//   mask: [             // array of masks
//     '+7 *** ***-**-**',
//     '+7 (***) ***-**-**'
//   ],
//   value: 'RU'         // country code
// }

// Get information about USA
const usaPhone = GeoPhone.get('US')
console.log(usaPhone)
// {
//   phone: 1,
//   within: 1,
//   mask: ['+1 (***) ***-****'],
//   value: 'US'
// }

// Get information about non-existent country
const unknown = GeoPhone.get('XX')
console.log(unknown) // undefined
```

### `getByPhone`

Gets information by phone number.

**Parameters:**
- `phone: string` — phone number

**Returns:** `GeoPhoneMapInfo` — object with number information

```javascript
// Analyze Russian number
const russianNumber = GeoPhone.getByPhone('+79161234567')
console.log(russianNumber)
// {
//   item: {
//     items: [...],      // array of possible countries
//     info: {...},       // main information
//     value: 'RU',       // country code
//     mask: [...],       // available masks
//     maskFull: [...],   // full masks
//     next: {...}        // next possible digits
//   },
//   phone: '9161234567'  // number without country code
// }

// Analyze American number
const americanNumber = GeoPhone.getByPhone('+12125551234')
console.log(americanNumber)
// {
//   item: { value: 'US', ... },
//   phone: '2125551234'
// }

// Analyze partial number
const partialNumber = GeoPhone.getByPhone('+7916')
console.log(partialNumber)
// {
//   item: { value: 'RU', ... },
//   phone: '916'
// }
```

### `getByCode`

Gets complete mask data by country code.

**Parameters:**
- `code: string` — country and language code

**Returns:** `GeoPhoneMap | undefined` — object with mask data or undefined

```javascript
// Get mask for Russia
const russiaMask = GeoPhone.getByCode('RU')
console.log(russiaMask)
// {
//   items: [...],        // array of items
//   info: {...},         // country information
//   value: 'RU',         // country code
//   mask: [              // masks with internal symbols
//     '+7 ~ *** ***-**-**',
//     '+7 (~***) ***-**-**'
//   ],
//   maskFull: [          // full masks
//     '+7 * *** ***-**-**',
//     '+7 (****) ***-**-**'
//   ],
//   next: {...}          // possible next digits
// }

// Get mask for Germany
const germanyMask = GeoPhone.getByCode('DE')
console.log(germanyMask?.mask) // ['+49 *** ******', ...]
```

### `getList`

Gets an array from the list of all phone codes.

**Returns:** `GeoPhoneValue[]` — array of all phone codes

```javascript
// Get complete list
const allPhones = GeoPhone.getList()
console.log(allPhones.length) // number of countries with phone codes

// Example data structure
console.log(allPhones[0])
// {
//   phone: 1,             // country code
//   within: 1,            // internal code
//   mask: ['+1 (***) ***-****'],
//   value: 'US'           // country code
// }

// Find countries with code +7
const code7Countries = allPhones.filter(item => item.phone === 7)
console.log(code7Countries) // Russia, Kazakhstan
```

### `getMap`

Gets a tree map sorted by codes.

**Returns:** `Record<string, GeoPhoneMap>` — search tree map

```javascript
// Get complete map
const phoneMap = GeoPhone.getMap()

// Navigate tree for number +7916...
console.log(phoneMap['7'])        // information about code +7
console.log(phoneMap['7'].next)   // possible next digits
console.log(phoneMap['7'].next['9']) // information about +79...

// Check available codes
const availableCodes = Object.keys(phoneMap)
console.log(availableCodes) // ['1', '7', '33', '49', ...]
```

### `toMask`

Convert number to mask format.

**Parameters:**
- `phone: string` — phone number
- `masks?: string[]` — array of masks for conversion

**Returns:** `string | undefined` — formatted number or undefined

```javascript
// Format Russian number
const ruMasks = ['+7 (***) ***-**-**', '+7 *** ***-**-**']
const formatted1 = GeoPhone.toMask('9161234567', ruMasks)
console.log(formatted1) // '+7 (916) 123-45-67'

// Format American number
const usMasks = ['+1 (***) ***-****']
const formatted2 = GeoPhone.toMask('2125551234', usMasks)
console.log(formatted2) // '+1 (212) 555-1234'

// Format with inappropriate mask
const wrongFormat = GeoPhone.toMask('123', usMasks)
console.log(wrongFormat) // undefined (length doesn't match)

// Automatic detection and formatting
const phoneInfo = GeoPhone.getByPhone('+79161234567')
if (phoneInfo.item && phoneInfo.phone) {
  const autoFormatted = GeoPhone.toMask(phoneInfo.phone, phoneInfo.item.mask)
  console.log(autoFormatted) // '+7 ~ 916 123-45-67'
}
```

### `removeZero`

Removes country code from input number.

**Parameters:**
- `phone: string` — phone number

**Returns:** `string` — number without leading symbols

```javascript
// Remove leading zero
const withZero = GeoPhone.removeZero('09161234567')
console.log(withZero) // '9161234567'

// Replace 8 with 9 for Russian numbers
const withEight = GeoPhone.removeZero('89161234567')
console.log(withEight) // '9161234567'

// Number without changes
const normal = GeoPhone.removeZero('9161234567')
console.log(normal) // '9161234567'

// International number without changes
const international = GeoPhone.removeZero('+79161234567')
console.log(international) // '+79161234567'
```

## Practical Examples

### Phone Input Component

```javascript
class PhoneInput {
  constructor(inputElement, countryCode = 'US') {
    this.input = inputElement
    this.countryCode = countryCode
    this.setupMask()
    this.attachEvents()
  }

  setupMask() {
    const phoneData = GeoPhone.get(this.countryCode)
    if (phoneData?.mask.length) {
      this.currentMask = phoneData.mask[0]
      this.input.placeholder = this.currentMask
    }
  }

  attachEvents() {
    this.input.addEventListener('input', (e) => {
      const value = e.target.value.replace(/\D/g, '')
      const phoneData = GeoPhone.get(this.countryCode)
      const formatted = GeoPhone.toMask(value, phoneData?.mask)
      if (formatted) e.target.value = formatted
    })
  }
}

// Usage
new PhoneInput(document.getElementById('phone'), 'US')
```

### Phone Number Validator

```javascript
const validator = {
  validate(phone, countryCode) {
    const phoneInfo = GeoPhone.getByPhone(phone)
    if (!phoneInfo.item) return { isValid: false, error: 'Unknown country' }

    const isValidLength = phoneInfo.item.mask.some(mask => {
      const requiredLength = mask.replace(/[^*]/g, '').length
      return phoneInfo.phone.length === requiredLength
    })

    return {
      isValid: isValidLength,
      country: phoneInfo.item.value,
      formatted: GeoPhone.toMask(phoneInfo.phone, phoneInfo.item.mask)
    }
  }
}

// Usage
console.log(validator.validate('+12125551234')) // { isValid: true, ... }
```

### Phone Number Analyzer

```javascript
const analyzer = {
  extractPhones(text) {
    const patterns = [
      /\+\d{1,3}\s*\(?\d{1,4}\)?\s*[\d\s\-\(\)]{6,}/g,
      /\b\d{3}[\s\-]?\d{3}[\s\-]?\d{4}\b/g
    ]

    const found = new Set()
    patterns.forEach(pattern => {
      const matches = text.match(pattern) || []
      matches.forEach(match => found.add(match.trim()))
    })

    return Array.from(found).map(phone => ({
      original: phone,
      analysis: GeoPhone.getByPhone(phone)
    }))
  }
}

// Usage
const phones = analyzer.extractPhones('Call: +1 (212) 555-1234')
console.log(phones) // Found numbers with analysis
```

The GeoPhone class provides a powerful toolkit for working with phone numbers, including validation, formatting, country detection, and number analysis with support for international standards.
