"""Shared rune handling and deliberately small LP1-only ranking model."""
from pathlib import Path
import re
import numpy as np
ROOT=Path(__file__).resolve().parent
R='ᚠᚢᚦᚩᚱᚳᚷᚹᚻᚾᛁᛄᛇᛈᛉᛋᛏᛒᛖᛗᛚᛝᛟᛞᚪᚫᚣᛡᛠ'
LET='F U TH O R K G W H N I J EO P X S T B E M L ING OE D A AE Y IO EA'.split()
raw=(ROOT/'liber-primus__transcription--master.txt').read_text()
pages=raw[raw.index('ᚱ-'):].split('%')[:73];lp=pages[15:]
def vals(s):return np.array([R.index(c) for c in s if c in R],dtype=np.int64)
def render(s,v):
    it=iter(v);out=''.join(LET[int(next(it))] if c in R else c for c in s)
    return re.sub(r'[-.&$§;,%]+',' ',out.replace('/\n','').replace('/','').replace('\n','')).strip()
sv=np.ones(400000,bool);sv[:2]=False
for i in range(2,633):
    if sv[i]:sv[i*i::i]=False
pr=np.flatnonzero(sv);N=18000
phi=np.arange(N)
for i in range(2,N):
    if phi[i]==i:phi[i::i]-=phi[i::i]//i
fib=np.zeros(N,dtype=np.int64);fib[1]=1
for i in range(2,N):fib[i]=(fib[i-1]+fib[i-2])%29
SEQS={'prime':pr[:N]%29,'prime_minus_one':(pr[:N]-1)%29,'fibonacci':fib,
      'integer_totient':phi%29,'integer':np.arange(N)%29,'square':np.arange(N)**2%29,
      'cumulative_prime':np.cumsum(pr[:N])%29,'prime_gap':np.diff(pr[:N+1])%29}
train=[(28-vals(pages[0]))%29]+[(2-vals(pages[i]))%29 for i in range(4,8)]+[vals(pages[i]) for i in [3,8,9,10,11,14]]
bi=np.full((29,29),0.2);tri=np.full((29,29,29),0.2)
for t in train:
    for a,b in zip(t,t[1:]):bi[a,b]+=1
    for a,b,c in zip(t,t[1:],t[2:]):tri[a,b,c]+=1
bi=np.log(bi/bi.sum(axis=1,keepdims=True));tri=np.log(tri/tri.sum(axis=2,keepdims=True))
def scores(v):return bi[v[:,:-1],v[:,1:]].mean(axis=1)+tri[v[:,:-2],v[:,1:-1],v[:,2:]].mean(axis=1)
def positions(text,reset='',advance='',skip_f=False):
    """Whitespace and non-runic alphanumerics do not consume key positions."""
    k=0;idx=[];reset_flags=[];pending=False
    for c in text:
        if c in R:
            idx.append(k);reset_flags.append(pending);pending=False
            if not(skip_f and c==R[0]):k+=1
        elif c in reset:k=0;pending=True
        elif c in advance:k+=1
    return np.array(idx),np.array(reset_flags)
def without_first_clauses(text):
    return '&'.join(s.split('.',1)[1] if '.' in s else s for s in text.split('&'))
