1use std::collections::HashMap;
2use std::sync::OnceLock;
3
4fn ddd_map() -> &'static HashMap<&'static str, (&'static str, &'static str)> {
5 static DDD_MAP: OnceLock<HashMap<&str, (&str, &str)>> = OnceLock::new();
6 DDD_MAP.get_or_init(|| {
7 let mut map = HashMap::new();
8
9 map.insert("61", ("Distrito Federal", "Centro-Oeste"));
11 map.insert("62", ("Goiás", "Centro-Oeste"));
12 map.insert("64", ("Goiás", "Centro-Oeste"));
13 map.insert("65", ("Mato Grosso", "Centro-Oeste"));
14 map.insert("66", ("Mato Grosso", "Centro-Oeste"));
15 map.insert("67", ("Mato Grosso do Sul", "Centro-Oeste"));
16
17 map.insert("82", ("Alagoas", "Nordeste"));
19 map.insert("71", ("Bahia", "Nordeste"));
20 map.insert("73", ("Bahia", "Nordeste"));
21 map.insert("74", ("Bahia", "Nordeste"));
22 map.insert("75", ("Bahia", "Nordeste"));
23 map.insert("77", ("Bahia", "Nordeste"));
24 map.insert("85", ("Ceará", "Nordeste"));
25 map.insert("88", ("Ceará", "Nordeste"));
26 map.insert("98", ("Maranhão", "Nordeste"));
27 map.insert("99", ("Maranhão", "Nordeste"));
28 map.insert("83", ("Paraíba", "Nordeste"));
29 map.insert("81", ("Pernambuco", "Nordeste"));
30 map.insert("87", ("Pernambuco", "Nordeste"));
31 map.insert("86", ("Piauí", "Nordeste"));
32 map.insert("89", ("Piauí", "Nordeste"));
33 map.insert("84", ("Rio Grande do Norte", "Nordeste"));
34 map.insert("79", ("Sergipe", "Nordeste"));
35
36 map.insert("68", ("Acre", "Norte"));
38 map.insert("96", ("Amapá", "Norte"));
39 map.insert("92", ("Amazonas", "Norte"));
40 map.insert("97", ("Amazonas", "Norte"));
41 map.insert("91", ("Pará", "Norte"));
42 map.insert("93", ("Pará", "Norte"));
43 map.insert("94", ("Pará", "Norte"));
44 map.insert("69", ("Rondônia", "Norte"));
45 map.insert("95", ("Roraima", "Norte"));
46 map.insert("63", ("Tocantins", "Norte"));
47
48 map.insert("27", ("Espírito Santo", "Sudeste"));
50 map.insert("28", ("Espírito Santo", "Sudeste"));
51 map.insert("31", ("Minas Gerais", "Sudeste"));
52 map.insert("32", ("Minas Gerais", "Sudeste"));
53 map.insert("33", ("Minas Gerais", "Sudeste"));
54 map.insert("34", ("Minas Gerais", "Sudeste"));
55 map.insert("35", ("Minas Gerais", "Sudeste"));
56 map.insert("37", ("Minas Gerais", "Sudeste"));
57 map.insert("38", ("Minas Gerais", "Sudeste"));
58 map.insert("21", ("Rio de Janeiro", "Sudeste"));
59 map.insert("22", ("Rio de Janeiro", "Sudeste"));
60 map.insert("24", ("Rio de Janeiro", "Sudeste"));
61 map.insert("11", ("São Paulo", "Sudeste"));
62 map.insert("12", ("São Paulo", "Sudeste"));
63 map.insert("13", ("São Paulo", "Sudeste"));
64 map.insert("14", ("São Paulo", "Sudeste"));
65 map.insert("15", ("São Paulo", "Sudeste"));
66 map.insert("16", ("São Paulo", "Sudeste"));
67 map.insert("17", ("São Paulo", "Sudeste"));
68 map.insert("18", ("São Paulo", "Sudeste"));
69 map.insert("19", ("São Paulo", "Sudeste"));
70
71 map.insert("41", ("Paraná", "Sul"));
73 map.insert("42", ("Paraná", "Sul"));
74 map.insert("43", ("Paraná", "Sul"));
75 map.insert("44", ("Paraná", "Sul"));
76 map.insert("45", ("Paraná", "Sul"));
77 map.insert("46", ("Paraná", "Sul"));
78 map.insert("51", ("Rio Grande do Sul", "Sul"));
79 map.insert("53", ("Rio Grande do Sul", "Sul"));
80 map.insert("54", ("Rio Grande do Sul", "Sul"));
81 map.insert("55", ("Rio Grande do Sul", "Sul"));
82 map.insert("47", ("Santa Catarina", "Sul"));
83 map.insert("48", ("Santa Catarina", "Sul"));
84 map.insert("49", ("Santa Catarina", "Sul"));
85
86 map
87 })
88}
89
90pub struct PhoneValidationResult {
91 pub is_valid: bool,
92 pub phone_type: Option<String>,
93 pub region: Option<String>,
94 pub state: Option<String>,
95}
96
97pub fn phone(phone: &str) -> PhoneValidationResult {
98 let cleaned: String = phone.chars().filter(|c| c.is_digit(10)).collect();
99 let length = cleaned.len();
100
101 let is_valid_length = length == 10 || length == 11;
102
103 if !is_valid_length {
104 return PhoneValidationResult {
105 is_valid: false,
106 phone_type: None,
107 region: None,
108 state: None,
109 };
110 }
111
112 let phone_type = if length == 10 {
113 Some("Fixo".to_string())
114 } else {
115 Some("Móvel".to_string())
116 };
117
118 let (state, region) = if length == 10 || length == 11 {
119 let ddd = &cleaned[0..2];
120 ddd_map().get(ddd).map_or((None, None), |&(s, r)| {
121 (Some(s.to_string()), Some(r.to_string()))
122 })
123 } else {
124 (None, None)
125 };
126
127 let is_valid = is_valid_length && state.is_some();
128
129 PhoneValidationResult {
130 is_valid,
131 phone_type,
132 region,
133 state,
134 }
135}