teqo-backup/src/lib/bahiaTseZones.ts
Francisco Ignácio Fontoura Solla ac7f2775cd Add opt-in TSE zone and territory suggestion chips for nuclei.
Ship A2 with a static Bahia municipality↔zone map, pure suggestion engine, and form chips that never auto-apply geography.
2026-07-18 20:04:04 -03:00

484 lines
12 KiB
TypeScript

/**
* Official Bahia municipality ↔ TSE electoral zone mapping.
*
* Source (TSE open data — Results 2024, detalhe da apuração por município e zona, UF BA):
* https://dadosabertos.tse.jus.br/dataset/resultados-2024
* https://cdn.tse.jus.br/estatistica/sead/odsele/detalhe_votacao_munzona/detalhe_votacao_munzona_2024.zip
* Entry: detalhe_votacao_munzona_2024_BA.csv
* Download SHA-256: 24e75fcf98a57b2362c33d46eb96b99a4b7070966cfc7f6398e12240e3f679f0
*
* Chosen over 2022 result files because TSE rezoning can change municipality↔zone
* assignments between cycles. 2024 municipal elections are the most recent
* election-validated BA coverage of all 417 municipalities (extracted 2026-07-18).
*
* Municipality spellings follow the canonical application names in bahiaTerritories.
* TSE variants (Camacan, Dias d'Ávila, Muquém de São Francisco, Santa Teresinha)
* were reconciled via canonicalizeMunicipalityName. Coverage is independently
* checked by the official test evidence fixture.
*/
import {
bahiaIdentityTerritories,
bahiaMunicipalities,
citiesForTerritory,
isBahiaMunicipality,
type BahiaIdentityTerritory,
} from '@/lib/bahiaTerritories'
export const bahiaMunicipalityTseZones: Readonly<Record<string, readonly number[]>> = {
'Abaíra': [105],
'Abaré': [158],
'Acajutiba': [21],
'Adustina': [52],
'Água Fria': [74],
'Aiquara': [147],
'Alagoinhas': [163],
'Alcobaça': [112],
'Almadina': [135],
'Amargosa': [36],
'Amélia Rodrigues': [192],
'América Dourada': [199],
'Anagé': [161],
'Andaraí': [119],
'Andorinha': [45],
'Angical': [126],
'Anguera': [157],
'Antas': [82],
'Antônio Cardoso': [143],
'Antônio Gonçalves': [53],
'Aporá': [44],
'Apuarema': [23],
'Araças': [200],
'Aracatu': [90],
'Araci': [123],
'Aramari': [163],
'Arataca': [166],
'Aratuípe': [30],
'Aurelino Leal': [73],
'Baianópolis': [126],
'Baixa Grande': [86],
'Banzaê': [110],
'Barra': [77],
'Barra da Estiva': [169],
'Barra do Choça': [139],
'Barra do Mendes': [176],
'Barra do Rocha': [134],
'Barreiras': [70, 75],
'Barro Alto': [174],
'Barro Preto': [136],
'Barrocas': [150],
'Belmonte': [34],
'Belo Campo': [177],
'Biritinga': [150],
'Boa Nova': [59],
'Boa Vista do Tupim': [42],
'Bom Jesus da Lapa': [71],
'Bom Jesus da Serra': [59],
'Boninal': [105],
'Bonito': [69],
'Boquira': [65],
'Botuporã': [168],
'Brejões': [36],
'Brejolândia': [190],
'Brotas de Macaúbas': [94],
'Brumado': [90],
'Buerarema': [166],
'Buritirama': [77],
'Caatiba': [201],
'Cabaceiras do Paraguaçu': [131],
'Cachoeira': [118],
'Caculé': [93],
'Caém': [167],
'Caetanos': [58],
'Caetité': [63],
'Cafarnaum': [55],
'Cairu': [31],
'Caldeirão Grande': [115],
'Camacan': [133],
'Camaçari': [170, 171],
'Camamu': [78],
'Campo Alegre de Lourdes': [67],
'Campo Formoso': [53],
'Canápolis': [99],
'Canarana': [174],
'Canavieiras': [116],
'Candeal': [114],
'Candeias': [127],
'Candiba': [64],
'Cândido Sales': [40],
'Cansanção': [50],
'Canudos': [83],
'Capela do Alto Alegre': [196],
'Capim Grosso': [191],
'Caraíbas': [161],
'Caravelas': [112],
'Cardeal da Silva': [144],
'Carinhanha': [125],
'Casa Nova': [66],
'Castro Alves': [43],
'Catolândia': [100],
'Catu': [129],
'Caturama': [111],
'Central': [159],
'Chorrochó': [158],
'Cícero Dantas': [82],
'Cipó': [79],
'Coaraci': [135],
'Cocos': [61],
'Conceição da Feira': [108],
'Conceição do Almeida': [184],
'Conceição do Coité': [132],
'Conceição do Jacuípe': [192],
'Conde': [21],
'Condeúba': [60],
'Contendas do Sincorá': [58],
'Coração de Maria': [130],
'Cordeiros': [60],
'Coribe': [61],
'Coronel João Sá': [52],
'Correntina': [124],
'Cotegipe': [98],
'Cravolândia': [38],
'Crisópolis': [81],
'Cristópolis': [126],
'Cruz das Almas': [142],
'Curaçá': [85],
'Dário Meira': [147],
"Dias d'Ávila": [186],
'Dom Basílio': [101],
'Dom Macedo Costa': [202],
'Elísio Medrado': [107],
'Encruzilhada': [152],
'Entre Rios': [144],
'Érico Cardoso': [111],
'Esplanada': [21],
'Euclides da Cunha': [102],
'Eunápolis': [188, 203],
'Fátima': [82],
'Feira da Mata': [125],
'Feira de Santana': [154, 155, 156, 157],
'Filadélfia': [149],
'Firmino Alves': [137],
'Floresta Azul': [29],
'Formosa do Rio Preto': [187],
'Gandu': [151],
'Gavião': [191],
'Gentio do Ouro': [68],
'Glória': [84],
'Gongogi': [73],
'Governador Mangabeira': [131],
'Guajeru': [93],
'Guanambi': [64],
'Guaratinga': [189],
'Heliópolis': [110],
'Iaçu': [193],
'Ibiassucê': [93],
'Ibicaraí': [29],
'Ibicoara': [169],
'Ibicuí': [146],
'Ibipeba': [176],
'Ibipitanga': [65],
'Ibiquera': [42],
'Ibirapitanga': [134],
'Ibirapuã': [153],
'Ibirataia': [24],
'Ibitiara': [88],
'Ibititá': [104],
'Ibotirama': [173],
'Ichu': [132],
'Igaporã': [168],
'Igrapiúna': [32],
'Iguaí': [146],
'Ilhéus': [25, 26],
'Inhambupe': [44],
'Ipecaetá': [143],
'Ipiaú': [24],
'Ipirá': [62],
'Ipupiara': [94],
'Irajuba': [76],
'Iramaia': [169],
'Iraquara': [89],
'Irará': [74],
'Irecê': [95],
'Itabela': [189],
'Itaberaba': [42],
'Itabuna': [27, 28],
'Itacaré': [198],
'Itaeté': [119],
'Itagi': [147],
'Itagibá': [147],
'Itagimirim': [188],
'Itaguaçu da Bahia': [68],
'Itaju do Colônia': [137],
'Itajuípe': [136],
'Itamaraju': [172],
'Itamari': [151],
'Itambé': [201],
'Itanagra': [185],
'Itanhém': [148],
'Itaparica': [141],
'Itapé': [27],
'Itapebi': [188],
'Itapetinga': [140],
'Itapicuru': [81],
'Itapitanga': [135],
'Itaquara': [76],
'Itarantim': [138],
'Itatim': [107],
'Itiruçu': [37],
'Itiúba': [149],
'Itororó': [137],
'Ituaçu': [58],
'Ituberá': [32],
'Iuiú': [175],
'Jaborandi': [61],
'Jacaraci': [92],
'Jacobina': [46],
'Jaguaquara': [76],
'Jaguarari': [179],
'Jaguaripe': [30],
'Jandaíra': [49],
'Jequié': [22, 23],
'Jeremoabo': [51],
'Jiquiriçá': [109],
'Jitaúna': [24],
'João Dourado': [199],
'Juazeiro': [47, 48],
'Jucuruçu': [172],
'Jussara': [159],
'Jussari': [28],
'Jussiape': [101],
'Lafaiete Coutinho': [23],
'Lagoa Real': [63],
'Laje': [109],
'Lajedão': [153],
'Lajedinho': [87],
'Lajedo do Tabocal': [37],
'Lamarão': [160],
'Lapão': [104],
'Lauro de Freitas': [180],
'Lençóis': [89],
'Licínio de Almeida': [117],
'Livramento de Nossa Senhora': [101],
'Luís Eduardo Magalhães': [205],
'Macajuba': [87],
'Macarani': [91],
'Macaúbas': [65],
'Macururé': [158],
'Madre de Deus': [162],
'Maetinga': [161],
'Maiquinique': [91],
'Mairi': [86],
'Malhada': [125],
'Malhada de Pedras': [90],
'Manoel Vitorino': [22],
'Mansidão': [97],
'Maracás': [37],
'Maragogipe': [118],
'Maraú': [78],
'Marcionílio Souza': [193],
'Mascote': [133],
'Mata de São João': [185],
'Matina': [113],
'Medeiros Neto': [153],
'Miguel Calmon': [103],
'Milagres': [193],
'Mirangaba': [167],
'Mirante': [59],
'Monte Santo': [50],
'Morpará': [173],
'Morro do Chapéu': [55],
'Mortugaba': [92],
'Mucugê': [119],
'Mucuri': [35],
'Mulungu do Morro': [55],
'Mundo Novo': [54],
'Muniz Ferreira': [202],
'Muquém de São Francisco': [98],
'Muritiba': [131],
'Mutuípe': [109],
'Nazaré': [30],
'Nilo Peçanha': [32],
'Nordestina': [106],
'Nova Canaã': [146],
'Nova Fátima': [196],
'Nova Ibiá': [151],
'Nova Itarana': [36],
'Nova Redenção': [119],
'Nova Soure': [79],
'Nova Viçosa': [35],
'Novo Horizonte': [88],
'Novo Triunfo': [82],
'Olindina': [81],
'Oliveira dos Brejinhos': [94],
'Ouriçangas': [74],
'Ourolândia': [167],
'Palmas de Monte Alto': [175],
'Palmeiras': [89],
'Paramirim': [111],
'Paratinga': [173],
'Paripiranga': [52],
'Pau Brasil': [133],
'Paulo Afonso': [84, 181],
'Pé de Serra': [114],
'Pedrão': [130],
'Pedro Alexandre': [51],
'Piatã': [105],
'Pilão Arcado': [195],
'Pindaí': [117],
'Pindobaçu': [115],
'Pintadas': [62],
'Piraí do Norte': [151],
'Piripá': [177],
'Piritiba': [54],
'Planaltino': [37],
'Planalto': [139],
'Poções': [59],
'Pojuca': [200],
'Ponto Novo': [149],
'Porto Seguro': [121, 122],
'Potiraguá': [138],
'Prado': [112],
'Presidente Dutra': [95],
'Presidente Jânio Quadros': [60],
'Presidente Tancredo Neves': [197],
'Queimadas': [106],
'Quijingue': [102],
'Quixabeira': [191],
'Rafael Jambeiro': [43],
'Remanso': [67],
'Retirolândia': [196],
'Riachão das Neves': [182],
'Riachão do Jacuípe': [114],
'Riacho de Santana': [113],
'Ribeira do Amparo': [79],
'Ribeira do Pombal': [110],
'Ribeirão do Largo': [152],
'Rio de Contas': [101],
'Rio do Antônio': [93],
'Rio do Pires': [111],
'Rio Real': [49],
'Rodelas': [158],
'Ruy Barbosa': [87],
'Salinas da Margarida': [30],
'Salvador': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
'Santa Bárbara': [160],
'Santa Brígida': [181],
'Santa Cruz Cabrália': [121],
'Santa Cruz da Vitória': [29],
'Santa Inês': [38],
'Santa Luzia': [133],
'Santa Maria da Vitória': [72],
'Santa Rita de Cássia': [97],
'Santa Teresinha': [107],
'Santaluz': [145],
'Santana': [99],
'Santanópolis': [74],
'Santo Amaro': [178],
'Santo Antônio de Jesus': [56, 202],
'Santo Estêvão': [143],
'São Desidério': [100],
'São Domingos': [120],
'São Felipe': [184],
'São Félix': [118],
'São Félix do Coribe': [72],
'São Francisco do Conde': [162],
'São Gabriel': [95],
'São Gonçalo dos Campos': [108],
'São José da Vitória': [166],
'São José do Jacuípe': [191],
'São Miguel das Matas': [36],
'São Sebastião do Passé': [128],
'Sapeaçu': [142],
'Sátiro Dias': [44],
'Saubara': [178],
'Saúde': [115],
'Seabra': [88],
'Sebastião Laranjeiras': [175],
'Senhor do Bonfim': [45],
'Sento Sé': [96],
'Serra do Ramalho': [71],
'Serra Dourada': [190],
'Serra Preta': [155],
'Serrinha': [150],
'Serrolândia': [46],
'Simões Filho': [33],
'Sítio do Mato': [71],
'Sítio do Quinto': [51],
'Sobradinho': [66],
'Souto Soares': [174],
'Tabocas do Brejo Velho': [190],
'Tanhaçu': [58],
'Tanque Novo': [168],
'Tanquinho': [160],
'Taperoá': [32],
'Tapiramutá': [54],
'Teixeira de Freitas': [183],
'Teodoro Sampaio': [130],
'Teofilândia': [123],
'Teolândia': [197],
'Terra Nova': [128],
'Tremedal': [177],
'Tucano': [80],
'Uauá': [83],
'Ubaíra': [38],
'Ubaitaba': [73],
'Ubatã': [134],
'Uibaí': [159],
'Umburanas': [167],
'Una': [116],
'Urandi': [117],
'Uruçuca': [198],
'Utinga': [69],
'Valença': [31],
'Valente': [120],
'Várzea da Roça': [86],
'Várzea do Poço': [103],
'Várzea Nova': [55],
'Varzedo': [56],
'Vera Cruz': [141],
'Vereda': [148],
'Vitória da Conquista': [39, 40, 41],
'Wagner': [69],
'Wanderley': [98],
'Wenceslau Guimarães': [197],
'Xique-Xique': [68],
} as const
const emptyZones: readonly number[] = []
export const tseZonesForCity = (city: string): readonly number[] => {
if (!isBahiaMunicipality(city)) return emptyZones
return bahiaMunicipalityTseZones[city] ?? emptyZones
}
const citiesByZone = new Map<number, string[]>()
for (const city of bahiaMunicipalities) {
for (const zone of bahiaMunicipalityTseZones[city] ?? []) {
const list = citiesByZone.get(zone)
if (list) list.push(city)
else citiesByZone.set(zone, [city])
}
}
for (const list of citiesByZone.values()) {
list.sort((left, right) => left.localeCompare(right, 'pt-BR'))
}
const zonesByTerritory = new Map<string, readonly number[]>()
for (const territory of bahiaIdentityTerritories) {
const zones = new Set<number>()
for (const city of citiesForTerritory(territory)) {
for (const zone of tseZonesForCity(city)) zones.add(zone)
}
zonesByTerritory.set(
territory,
[...zones].sort((left, right) => left - right),
)
}
export const tseZonesForTerritory = (
territory: BahiaIdentityTerritory,
): readonly number[] => zonesByTerritory.get(territory) ?? emptyZones
export const citiesForTseZone = (zoneNumber: number): readonly string[] =>
citiesByZone.get(zoneNumber) ?? []