"""Name normalisation shared by both sides (realtycheck JPPH-style names, catalogue EdgeProp-style names)."""
import re

ABBR = {
    'tmn': 'taman', 'tman': 'taman', 'tamn': 'taman', 'jln': 'jalan', 'jl': 'jalan', 'jalan2': 'jalan',
    'kg': 'kampung', 'kpg': 'kampung', 'kmpg': 'kampung', 'kampong': 'kampung',
    'bdr': 'bandar', 'bndr': 'bandar', 'sg': 'sungai', 'sgi': 'sungai', 'bkt': 'bukit', 'bt': 'batu',
    'sek': 'seksyen', 'seksen': 'seksyen', 'sekysen': 'seksyen', 'sect': 'seksyen', 'section': 'seksyen', 'sec': 'seksyen',
    'ph': 'phase', 'presint': 'precinct', 'prec': 'precinct', 'fasa': 'phase', 'fase': 'phase', 'phs': 'phase',
    'pgsp': 'pangsapuri', 'pngsapuri': 'pangsapuri', 'psp': 'pangsapuri',
    'apt': 'apartment', 'apts': 'apartment', 'apartments': 'apartment', 'apartmen': 'apartment', 'appartment': 'apartment',
    'kondo': 'condominium', 'kondominium': 'condominium', 'condo': 'condominium', 'condominiums': 'condominium',
    'residensi': 'residence', 'residences': 'residence', 'residency': 'residence', 'residens': 'residence', 'resi': 'residence',
    'rsdn': 'residence', 'suites': 'suite', 'svc': 'service', 'serviced': 'service', 'servis': 'service',
    'flats': 'flat', 'rumah': 'rumah', 'pangsa': 'pangsa', 'blk': 'blok', 'block': 'blok', 'townhouses': 'townhouse', 'twnhse': 'townhouse',
    'ind': 'industri', 'industrial': 'industri', 'perindustrian': 'industri', 'indust': 'industri',
    'mt': 'mount', 'hts': 'heights', 'ht': 'heights', 'gdn': 'garden', 'gdns': 'garden', 'gardens': 'garden',
    'twr': 'tower', 'towers': 'tower', 'ctr': 'centre', 'center': 'centre', 'pk': 'park', 'ave': 'avenue',
    'mk': 'mukim', 'kws': 'kawasan', 'perumahan': 'perumahan', 'pusat': 'pusat', 'bdn': 'bandar',
    'kl': 'kuala lumpur', 'pj': 'petaling jaya', 'jb': 'johor bahru', 'ttdi': 'ttdi',
    'sri': 'seri', 'sre': 'seri', 'precint': 'precinct', 'abd': 'abdul', 'hj': 'haji', 'kpg.': 'kampung', 'lbh': 'lebuh', 'psn': 'persiaran', 'tg': 'tanjung', 'tanjong': 'tanjung', 'kampung2': 'kampung'
}
NUM_WORDS = {'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5', 'six': '6', 'seven': '7', 'eight': '8',
             'nine': '9', 'ten': '10', 'satu': '1', 'dua': '2', 'tiga': '3', 'empat': '4', 'lima': '5', 'enam': '6',
             'tujuh': '7', 'lapan': '8', 'sembilan': '9', 'sepuluh': '10',
             'ii': '2', 'iii': '3', 'iv': '4', 'vi': '6', 'vii': '7', 'viii': '8', 'ix': '9'}
# Words that say WHAT the building is, not WHICH one. Stripped from the core name.
TYPE_WORDS = {'apartment', 'condominium', 'pangsapuri', 'residence', 'flat', 'rumah', 'pangsa', 'service', 'suite',
              'soho', 'sovo', 'sofo', 'the', 'and', 'of', 'at', 'di', 'kedai', 'shop', 'shops', 'office', 'pejabat',
              'industri', 'kilang', 'factory', 'kos', 'rendah', 'sederhana', 'murah', 'teres', 'terrace', 'semi', 'd',
              'detached', 'bungalow', 'banglo', 'berkembar', 'house', 'houses', 'homes', 'home', 'lot', 'lots',
              'pecahan', 'mukim', 'new', 'project', 'unit', 'units', 'blok', 'no'}
# Words that say it is a neighbourhood — kept, but weigh little.
GENERIC = {'taman', 'bandar', 'kampung', 'jalan', 'desa', 'seksyen', 'phase', 'baru', 'jaya', 'indah', 'seri', 'utama',
           'perdana', 'permai', 'bukit', 'sungai', 'batu', 'park', 'garden', 'heights', 'kawasan', 'perumahan',
           'lorong', 'persiaran', 'lebuh', 'lebuhraya', 'pusat', 'tower', 'court', 'villa', 'avenue', 'city', 'square',
           'central', 'centre', 'hill', 'hills', 'mutiara', 'damai', 'sentosa', 'mewah', 'setia', 'emas', 'harmoni',
           'bestari', 'makmur', 'intan', 'delima', 'melati', 'mawar', 'cempaka', 'kenanga', 'kiara', 'impian',
           'sejahtera', 'sentral', 'residen', 'height', 'vista', 'view', 'point', 'one', 'precinct'}

LOT_RE = re.compile(r'\((?:[^)]*\b(?:lot|pt|hs|geran|grn|no|pl|p/l|pec|tr|td)\b[^)]*|[\d\s,/&-]+)\)')


def base_clean(name):
    s = (name or '').lower()
    s = s.replace('(new project)', ' ').replace('*', ' ')
    s = re.sub(r'\bs\.\s*alam\b', 'shah alam', s)
    s = re.sub(r'\bp\.\s*jaya\b', 'petaling jaya', s)
    s = re.sub(r'\bk\.\s*lumpur\b', 'kuala lumpur', s)
    s = re.sub(r'\bb\.\s*baru\b', 'bandar baru', s)
    s = s.replace('&', ' and ')
    return s


def tokens(s):
    s = re.sub(r"[’'`]", '', s)
    s = re.sub(r'(?<=[a-z])\.(?=[a-z])', ' ', s)         # w.t.k -> w t k handled below
    raw = re.findall(r'\d+[a-z]+\d+(?:-[a-z])?|[a-z]+\d*[a-z]*|\d+[a-z]*', s)
    out = []
    for t in raw:
        t = ABBR.get(t, t)
        for u in t.split():
            u = NUM_WORDS.get(u, u)
            out.append(u)
    # glue runs of single letters (w t k -> wtk)
    glued, buf = [], ''
    for t in out:
        if len(t) == 1 and t.isalpha():
            buf += t
        else:
            if buf:
                glued.append(buf); buf = ''
            glued.append(t)
    if buf:
        glued.append(buf)
    return glued


LOTX_RE = re.compile(r"\b(?:pt|lot|pl|p/l|tr|td|pn|hsd|geran|grn|pec|no)\.?\s*\d+[a-z]?(?:\s*(?:[,/&-]|and)\s*\d+[a-z]?)*\b")


def clean_full(name):
    s = base_clean(name)
    s = LOT_RE.sub(' ', s)
    return LOTX_RE.sub(' ', s)


def variants(name):
    """Readings of one name as (kind, tokens). kind: main | pre (before @ / ' - ' / ',') | inner (inside brackets)."""
    s_nolot = clean_full(name)
    out = [('main', s_nolot), ('main', re.sub(r'\([^)]*\)', ' ', s_nolot))]
    for inner in re.findall(r'\(([^)]*)\)', s_nolot):
        out.append(('inner', inner))
    for kind, v in list(out):
        if '@' in v:
            # Only the part BEFORE '@' is a name; after it is where it is ("Amber 1 @ Bukit Sentosa").
            out.append(('pre' if kind == 'main' else kind, v.split('@', 1)[0]))
    for kind, v in list(out):
        for sep in (' - ', ',', ' – ', ' / '):
            if sep in v:
                out.append(('pre' if kind == 'main' else kind, v.split(sep, 1)[0]))
    res, seen = [], set()
    for kind, v in out:
        tk = tokens(v)
        k = ' '.join(tk)
        if tk and k not in seen:
            seen.add(k); res.append((kind, tk))
    return res


LOC_PREV = {'seksyen', 'pju', 'pjs', 'ss', 'usj', 'jalan', 'lorong', 'batu', 'km', 'mile', 'blok', 'no', 'lot', 'mukim', 'mk',
            'persiaran', 'lebuh', 'kilometer', 'bu', 'jalan2'}
PHASE_PREV = {'phase', 'precinct', 'presint', 'parcel', 'peringkat', 'zon', 'zone'}


def identity_numbers(name):
    """(ids, loc) numbers in a name. ids = phase / block / brand numbers (TMN MUTIARA 2, CLIO 2, 10 MONT KIARA);
    loc = numbers that say WHERE (SEKSYEN 2, PJU 1, BATU 9). Lot and title numbers are dropped first."""
    toks = tokens(clean_full(name))
    ids, loc, prev = set(), set(), None
    for t in toks:
        tt = t
        if prev in PHASE_PREV and t in ('i', 'v', 'x'):
            tt = {'i': '1', 'v': '5', 'x': '10'}[t]
        if re.fullmatch(r'\d{1,3}[a-z]{0,2}', tt) or re.fullmatch(r'\d{1,3}[a-z]\d{0,2}(?:-[a-z])?', tt):
            (loc if prev in LOC_PREV else ids).add(tt)
        prev = t
    return ids, loc


HIGHRISE_WORDS = {'apartment', 'condominium', 'pangsapuri', 'flat', 'suite', 'soho', 'sovo', 'sofo', 'pangsa'}
LANDED_WORDS = {'teres', 'terrace', 'banglo', 'bungalow', 'berkembar', 'cluster', 'townhouse', 'semi'}
BUILDING_WORDS = {'tower', 'plaza', 'court', 'mall', 'heights', 'park', 'garden', 'villa', 'square', 'avenue',
                  'point', 'residence', 'suite', 'mansion', 'mansions', 'place', 'palace', 'regency', 'centre'}


def name_kind(name):
    tk = set(tokens(clean_full(name)))
    if tk & HIGHRISE_WORDS: return 'highrise'
    if tk & LANDED_WORDS: return 'landed'
    return None


def core(tks):
    return [t for t in tks if t not in TYPE_WORDS]


def numbers(tks):
    return {t for t in tks if any(c.isdigit() for c in t)}


# Neighbourhood adjectives: in Malaysian estate names an extra one of these means a DIFFERENT estate
# (Taman Nuri vs Taman Nuri Indah), so they may never be waved through as "just a location".
SUFFIX_ADJ = {'jaya', 'indah', 'baru', 'permai', 'utama', 'mewah', 'perdana', 'damai', 'sentosa', 'mutiara', 'emas',
              'setia', 'harmoni', 'bestari', 'makmur', 'intan', 'delima', 'seri', 'raya', 'mas', 'aman', 'murni', 'ria',
              'maju', 'bahagia', 'gemilang', 'cemerlang', 'impian', 'sejahtera', 'ehsan', 'mulia', 'puteri', 'putera',
              'putra', 'selatan', 'utara', 'timur', 'barat', 'tengah', 'lama', 'heights', 'park', 'garden', 'villa',
              'court', 'tower', 'hill', 'hills', 'vista', 'view', 'avenue', 'square', 'city', 'central', 'centre'}
NEIGHBOURHOOD = {'taman', 'bandar', 'kampung', 'jalan', 'desa', 'seksyen', 'phase', 'precinct', 'lorong', 'persiaran',
                 'lebuh', 'kawasan', 'perumahan', 'pusat', 'kota', 'lebuhraya', 'lingkaran', 'jln'}
PREFIX = {'taman', 'bandar', 'kampung'}
FLAT_W, CONDO_W, SERVICED_W = {'flat', 'pangsa'}, {'apartment', 'condominium', 'pangsapuri'}, {'soho', 'sovo', 'sofo', 'suite', 'service'}


def type_class(raw):
    """What the NAME says the building is: flat / condo / serviced, or None."""
    if raw & FLAT_W: return 'flat'
    if raw & SERVICED_W: return 'serviced'
    if raw & CONDO_W: return 'condo'
    return None
