from nameparser.config._invariants import assert_normalized

GIVEN_NAME_TITLES = frozenset({
    'aunt',
    'auntie',
    'brother',
    'dame',
    'father',
    'king',
    'maid',
    'master',
    'mother',
    'pope',
    'queen',
    'sir',
    'sister',
    'uncle',
    'sheikh',
    'sheik',
    'shaik',
    'shayk',
    'shaykh',
    'shaikh',
    'cheikh',
    'shekh',
    # #269: Arabic -- "الشيخ" ("the sheikh") is the native-script form of
    # the transliterated sheikh/sheik/... cluster above; same
    # single-first-name-follows convention ("Sheikh Mohammed").
    'الشيخ',
    # #269 follow-up: Arabic honorifics precede the GIVEN name, so all
    # belong here rather than in plain TITLES. Article forms are never
    # given names; the bare doctor/professor/engineer forms are not
    # used as given names either. Deferred under the collision rule
    # (like мл/ст in suffixes.py): bare سيد (Sayyid is a common given
    # name), bare شيخ (Shaikha is a common female given name), أمير
    # and سلطان (Amir/Sultan, common given names), and the 'د.'
    # abbreviation -- edge-period normalization would leave bare 'د',
    # which swallows single-letter initials (the bare-κ trap above).
    'الدكتور',     # "the doctor" (m)
    'الدكتورة',    # "the doctor" (f)
    'دكتور',       # doctor (m), article-less
    'دكتورة',      # doctor (f), article-less
    'الأستاذ',     # "the professor"/Mr. honorific (m)
    'الأستاذة',    # professor/Mrs. honorific (f)
    'أستاذ',       # professor (m), article-less
    'أستاذة',      # professor (f), article-less
    'الحاج',       # hajj honorific (m)
    'الحاجة',      # hajj honorific (f)
    'الشيخة',      # female counterpart of الشيخ
    'مهندس',       # engineer (a genuine title in Egyptian usage)
})
"""
When these titles appear with a single other name, that name is a given name, e.g.
"Sir John", "Sister Mary", "Queen Elizabeth".
"""

# Maintainer note, deliberately a plain comment ABOVE the `#:` run and
# not inside it (a plain comment within a `#:` run splits it, and
# autodoc then drops everything above the split -- see particles.py).
# `#:` would publish this into the API reference, where it is advice to
# nobody. Frozen by
# construction (#293) -- `frozenset | set` returns a frozenset, the LEFT
# operand's type wins, so keep the frozenset first. Flipped, this
# silently yields a plain set again and unfreezes the constant.
#: **Cannot include things that could also be given names**, e.g. "dean".
#: Many of these from wikipedia: https://en.wikipedia.org/wiki/Title.
#: The parser recognizes chains of these including conjunctions allowing
#: recognition titles like "Deputy Secretary of State".
TITLES = GIVEN_NAME_TITLES | {
    "attaché",
    "chargé",
    "d'affaires",
    "king's",
    "marchioness",
    "marquess",
    "marquis",
    "marquise",
    "queen's",
    '10th',
    '1lt',
    '1sgt',
    '1st',
    '1stlt',
    '1stsgt',
    '2lt',
    '2nd',
    '2ndlt',
    '3rd',
    '4th',
    '5th',
    '6th',
    '7th',
    '8th',
    '9th',
    'a1c',
    'ab',
    'abbess',
    'abbot',
    'abolitionist',
    'academic',
    'acolyte',
    'activist',
    'actor',
    'actress',
    'adept',
    'adjutant',
    'adm',
    'admiral',
    'advertising',
    'adviser',
    'advocate',
    'air',
    'akhoond',
    'alderman',
    'almoner',
    'ambassador',
    'amn',
    'analytics',
    'anarchist',
    'animator',
    'anthropologist',
    'appellate',
    'apprentice',
    'arbitrator',
    'archbishop',
    'archdeacon',
    'archdruid',
    'archduchess',
    'archduke',
    'archeologist',
    'architect',
    'arhat',
    'army',
    'arranger',
    'assistant',
    'assoc',
    'associate',
    'asst',
    'astronomer',
    'attache',
    'attorney',
    'author',
    'award-winning',
    'ayatollah',
    'baba',
    'bailiff',
    'ballet',
    'bandleader',
    'banker',
    'banner',
    'bard',
    'baron',
    'baroness',
    'barrister',
    'baseball',
    'bearer',
    'behavioral',
    'bench',
    'bg',
    'bgen',
    'biblical',
    'bibliographer',
    'biochemist',
    'biographer',
    'biologist',
    'bishop',
    'blessed',
    'blogger',
    'blues',
    'bodhisattva',
    'bookseller',
    'botanist',
    'bp',
    'brigadier',
    'briggen',
    'british',
    'broadcaster',
    'buddha',
    'burgess',
    'burlesque',
    'business',
    'businessman',
    'businesswoman',
    'bwana',
    'canon',
    'capt',
    'captain',
    'cardinal',
    'cartographer',
    'cartoonist',
    'catholicos',
    'ccmsgt',
    'cdr',
    'celebrity',
    'ceo',
    'cfo',
    'chair',
    'chairs',
    'chancellor',
    'chaplain',
    'charge',  # unaccented 'chargé', like attaché/'attache'
    'chef',
    'chemist',
    'chief',
    'chieftain',
    'choreographer',
    'civil',
    'classical',
    'clergyman',
    'clerk',
    'cmsaf',
    'cmsgt',
    'co-chair',
    'co-chairs',
    'co-founder',
    'coach',
    'col',
    'collector',
    'colonel',
    'comedian',
    'comedienne',
    'comic',
    'commander',
    'commander-in-chief',
    'commodore',
    'composer',
    'compositeur',
    'comptroller',
    'computer',
    'comtesse',
    'conductor',
    'consultant',
    'controller',
    'corporal',
    'corporate',
    'correspondent',
    'councillor',
    'counselor',
    'count',
    'countess',
    'courtier',
    'cpl',
    'cpo',
    'cpt',
    'credit',
    'criminal',
    'criminologist',
    'critic',
    'csm',
    'curator',
    'customs',
    'cwo-2',
    'cwo-3',
    'cwo-4',
    'cwo-5',
    'cwo2',
    'cwo3',
    'cwo4',
    'cwo5',
    'cyclist',
    'dancer',
    'dcn',
    'deacon',
    'delegate',
    'deputy',
    'designated',
    'designer',
    'detective',
    'developer',
    'dhr',
    'dipl.-ing',
    'diplomat',
    'dir',
    'director',
    'discovery',
    'dissident',
    'district',
    'division',
    'docent',
    'docket',
    'doctor',
    'doyen',
    'dpty',
    'dr',
    'dra',
    'dramatist',
    'druid',
    'drummer',
    'duchesse',
    # 'duke', # a common first name
    'dutchess',
    'ecologist',
    'economist',
    'editor',
    'edler',
    'edmi',
    'edohen',
    'educator',
    'effendi',
    'ekegbian',
    'elerunwon',
    'eminence',
    'emperor',
    'empress',
    'engineer',
    'english',
    'ens',
    'entertainer',
    'entrepreneur',
    'envoy',
    'erzbischof',
    'essayist',
    'evangelist',
    'excellency',
    'excellent',
    'exec',
    'executive',
    'expert',
    'fadm',
    'family',
    'federal',
    'fh-prof',
    'field',
    'film',
    'financial',
    'first',
    'flag',
    'flying',
    'foreign',
    'forester',
    'founder',
    'fr',
    'frau',
    'fräulein',
    'freifrau',
    'freiherr',
    'friar',
    'frk',
    'frøken',
    'fru',
    'fürst',
    'fürsterzbischof',
    'gaf',
    'gen',
    'general',
    'generalissimo',
    'gentiluomo',
    'giani',
    'goodman',
    'goodwife',
    'governor',
    'graf',
    'gräfin',
    'grand',
    'großfürst',
    'group',
    'guitarist',
    'guru',
    'gyani',
    'gysgt',
    'hajji',
    'headman',
    'heir',
    'heiress',
    'her',
    'hereditary',
    'heren',
    'herr',
    'herzog',
    'herren',
    'herrn',
    'high',
    'highness',
    'his',
    'historian',
    'historicus',
    'historien',
    'holiness',
    'hon', # sorry Hon Solo, but judges seem more common.
    'honorable',
    'honourable',
    'host',
    'hr',
    'illustrator',
    'imam',
    'industrialist',
    'information',
    'instructor',
    'intelligence',
    'intendant',
    'inventor',
    'investigator',
    'investor',
    'journalist',
    'journeyman',
    'judge',
    'judicial',
    'jurist',
    'keyboardist',
    'kingdom',
    'knowledge',
    'lady',
    'lama',
    'lamido',
    'law',
    'lawyer',
    'lcdr',
    'lcpl',
    'leader',
    'lecturer',
    'legal',
    'librarian',
    'lieutenant',
    'linguist',
    'literary',
    'lord',
    'lt',
    'ltc',
    'ltcol',
    'ltg',
    'ltgen',
    'ltjg',
    'lyricist',
    'madam',
    'madame',
    'mademoiselle',
    'mag',
    'mag-judge',
    'mag/judge',
    'magistrate',
    'magistrate-judge',
    'magnate',
    'maharajah',
    'maharani',
    'mahdi',
    'maj',
    'majesty',
    'majgen',
    'manager',
    'marcher',
    'marchess',
    'marketing',
    'marquis',
    'mathematician',
    'mathematics',
    'matriarch',
    'mayor',
    'mcpo',
    'mcpoc',
    'mcpon',
    'md',
    'me',
    'member',
    'memoirist',
    'merchant',
    'met',
    'metropolitan',
    'mevr',
    'mevrouw',
    'mevrouwe',
    'mg',
    'mgr',
    'mgysgt',
    'military',
    'minister',
    'miss',
    'misses',
    'missionary',
    'mister',
    'mlle',
    'mme',
    'mobster',
    'model',
    'monk',
    'monseigneur',
    'monsieur',
    'monsignor',
    'most',
    'mountaineer',
    'mpco-cg',
    'mr',
    'mrs',
    'ms',
    'msg',
    'msgt',
    'mufti',
    'mullah',
    'municipal',
    'murshid',
    'musician',
    'musicologist',
    'mx',
    'mystery',
    'nanny',
    'narrator',
    'national',
    'naturalist',
    'navy',
    'neuroscientist',
    'novelist',
    'nurse',
    'obstetritian',
    'officer',
    'opera',
    'operating',
    'ornithologist',
    'painter',
    'paleontologist',
    'pastor',
    'patriarch',
    'pd',
    'pediatrician',
    'personality',
    'petty',
    'pfc',
    'pharaoh',
    'philantropist',
    'philosopher',
    'photographer',
    'physician',
    'physicist',
    'pianist',
    'pilot',
    'pioneer',
    'pir',
    'player',
    'playwright',
    'po1',
    'po2',
    'po3',
    'poet',
    'police',
    'political',
    'politician',
    'prefect',
    'prelate',
    'premier',
    'pres',
    'presbyter',
    'president',
    'presiding',
    'priest',
    'priestess',
    'primate',
    'prime',
    'prin',
    'prince',
    'princess',
    'principal',
    'printer',
    'printmaker',
    'prinz',
    'priv.-doz',
    'prior',
    'private',
    'pro',
    'producer',
    'prof',
    'professor',
    'provost',
    'pslc',
    'psychiatrist',
    'psychologist',
    'publisher',
    'pursuivant',
    'pv2',
    'pvt',
    'ra',
    'rabbi',
    'radio',
    'radm',
    'rangatira',
    'ranger',
    'rdml',
    'rear',
    'rebbe',
    'reichsgraf',
    'registrar',
    'rep',
    'representative',
    'researcher',
    'resident',
    'rev',
    'revenue',
    'reverend',
    'right',
    'risk',
    'ritter',
    'rock',
    'royal',
    'rt',
    'sa',
    'sailor',
    'saint',
    'sainte',
    'saoshyant',
    'satirist',
    'scholar',
    'schoolmaster',
    'scientist',
    'scpo',
    'screenwriter',
    'secretary',
    'security',
    'seigneur',
    'senator',
    'senhor',
    'senhora',
    'senhorita',
    'senior',
    'señor',
    'señora',
    'señores',
    'señorita',
    'señoritas',
    'senior-judge',
    'sergeant',
    'servant',
    'sfc',
    'sgm',
    'sgt',
    'sgtmaj',
    'sgtmajmc',
    'shehu',
    'sheikh',
    'sheriff',
    'siddha',
    'signor',
    'signora',
    'signore',
    'signorina',
    'singer',
    'singer-songwriter',
    'sma',
    'smsgt',
    'sn',
    'soccer',
    'social',
    'sociologist',
    'software',
    'soldier',
    'solicitor',
    'soprano',
    'spc',
    'speaker',
    'special',
    'sr',
    'sra',
    'srta',
    'srtas',
    'sres',
    'ssg',
    'ssgt',
    'st',
    'staff',
    'state',
    'states',
    'strategy',
    'subaltern',
    'subedar',
    'suffragist',
    'sultan',
    'sultana',
    'superior',
    'supreme',
    'surgeon',
    'swami',
    'swordbearer',
    'sysselmann',
    'tax',
    'teacher',
    'technical',
    'technologist',
    'television',
    'tenor',
    'theater',
    'theatre',
    'theologian',
    'theorist',
    'timi',
    'tirthankar',
    'translator',
    'travel',
    'treasurer',
    'tsar',
    'tsarina',
    'tsgt',
    'uk',
    'united',
    'univ.prof',
    'us',
    'vadm',
    'vardapet',
    'vc',
    'venerable',
    'verderer',
    'vicar',
    'vice',
    'viscount',
    'vizier',
    'vocalist',
    'voice',
    'vrouwe',
    'warden',
    'warrant',
    'wing',
    'wm',
    'wp',
    'wo-1',
    'wo1',
    'wo2',
    'wo3',
    'wo4',
    'wo5',
    'woodman',
    'writer',
    'zoologist',

    # #269: Cyrillic (ru/uk) -- mr/mrs/dr/prof/academician/pan(i)
    # honorifics, same title-then-family convention as 'mr'/'dr'/'prof'
    # above (not GIVEN_NAME_TITLES: "г-н Петров" families the surname
    # just like "Mr. Smith" does).
    'г-н',
    'г-жа',
    'д-р',
    'проф',
    'акад',
    'пан',
    'пані',

    # #269: Greek -- kyria/kyrios(abbr)/doctor/professor abbreviations;
    # same plain-title convention as above.
    # #269: bare κ deferred -- collides with the initial+surname shape
    # ('Κ. Παπαδόπουλος' would parse as title 'Κ.' with an empty given;
    # _normalize strips the edge period, so the entry matches the
    # initial). Latin TITLES deliberately has no bare single-letter
    # entries for the same reason.
    'κα',
    'κος',
    'δρ',
    'καθ',

    # #269: Hebrew -- "מר" ("Mr."), plain title like its Latin analog.
    # Geresh/gershayim forms of "doctor"/"Mrs." -- both the ASCII-quote
    # spelling ('ד"ר', "גב'") and the typographic Unicode spelling
    # ('ד״ר' U+05F4 gershayim, 'גב׳' U+05F3 geresh) ship: probed live
    # against extract_delimited's _open_ok/_close_ok boundary rules
    # (2026-07-17) -- the quote chars sit mid-word (no preceding
    # whitespace before the internal quote and, for the closing "'" one,
    # no following boundary), so both fail the open/close boundary test
    # and are left untouched as literal text. Extraction is provably
    # inert on these two ASCII spellings; no delimiter-interaction risk.
    'מר',
    'ד"ר',
    "גב'",
    'ד״ר',
    'גב׳',
    # #269 follow-up: the rest of the common Israeli honorifics, same
    # plain-title bucket (family follows) and the same dual geresh/
    # gershayim spelling rule as above. Deferred under the collision
    # rule: bare 'רב' (also the ordinary word "many"). The 'בר'
    # particle deferral is recorded in prefixes.py with the other
    # particle decisions.
    'גברת',       # Mrs./Ms., full form
    "פרופ'",      # professor abbreviation, ASCII apostrophe
    'פרופ׳',      # professor abbreviation, U+05F3 geresh
    'פרופסור',    # professor, full form
    'עו"ד',       # advocate/lawyer, ASCII quote
    'עו״ד',       # advocate/lawyer, U+05F4 gershayim
    'הרב',        # "the rabbi" (article form; bare רב deferred)

    # #269 follow-up: Devanagari (hi/mr). NO Latin twins on purpose:
    # transliterated sri/shri collide with real given names (Sri
    # Mulyani); the native-script forms cannot. "डॉ." matches via the
    # edge-period normalization, like Latin "Dr.".
    'श्री',        # Shri (Mr.)
    'श्रीमती',     # Shrimati (Mrs.)
    'डॉ',         # Dr. abbreviation
}


# Guard the invariants at import time, so a bad edit fails here instead of
# drifting silently until a test happens to catch it (see particles.py).
# The subset rule holds by construction today -- TITLES is defined as
# GIVEN_NAME_TITLES | {...} -- so this pins it against a future edit that
# makes TITLES a standalone set. Note `assert` is stripped under
# `python -O`, and unlike suffixes.py's relations this one has no
# runtime backstop: Lexicon deliberately does NOT validate
# given_name_titles against titles (its "NOT validated" comment gives
# the reasoning), so a caller's
# Lexicon(titles=frozenset({"sir"}), given_name_titles=frozenset({"dame"}))
# is accepted. Under -O nothing checks this relation at all.
assert GIVEN_NAME_TITLES <= TITLES, \
    "GIVEN_NAME_TITLES must stay a subset of TITLES"
# TITLES covers GIVEN_NAME_TITLES, by the subset assert above.
assert_normalized("TITLES", TITLES)


# 1.x name, deprecated in 2.2 and removed in 3.0 (#293). Unlike the
# module moves in #293, the constant did not change module, so this
# aliases a name to one of this module's own globals: a module
# __getattr__ runs only once the body has finished and the module is in
# sys.modules, so the lookup resolves rather than recursing.
from typing import TYPE_CHECKING  # noqa: E402

from nameparser.config._deprecated import alias_getattr  # noqa: E402

# Declared for the type checker, served by __getattr__ at runtime. The
# split is what keeps mypy checking this module's LIVE names: an
# assigned module __getattr__ answers every missing attribute, so a
# plain assignment here made `from ... import TITLE` type-check clean.
# See alias_getattr's docstring. Both branches go in 3.0.
if TYPE_CHECKING:
    FIRST_NAME_TITLES: frozenset[str]
else:
    __getattr__, __dir__ = alias_getattr(__name__, {
        "FIRST_NAME_TITLES": (
            "nameparser.config.titles", "GIVEN_NAME_TITLES"),
    })

# Star imports read __all__ and never the module __getattr__ -- see the
# note in prefixes.py. This module keeps its live constants, so they are
# listed too: without __all__ a star import bound them and dropped the
# retired name silently; with a PARTIAL __all__ it would bind the
# retired name and drop the live ones instead.
# Source order, not alphabetical -- see the note in suffixes.py.
__all__ = ["GIVEN_NAME_TITLES", "TITLES", "FIRST_NAME_TITLES"]
