"""Figures for the delta report (SVG + PNG). Estimates, not scores."""
import json,sys,numpy as np; from pathlib import Path
import matplotlib; matplotlib.use('Agg'); import matplotlib.pyplot as plt
S=Path(sys.argv[1]); A=S/'analysis'; F=S/'figures'; F.mkdir(exist_ok=True)
text={r['id']:r for r in json.load(open(A/'text-level.json'))}; audio=json.load(open(A/'audio-level.json')); blocks=json.load(open(A/'blocks.json'))
C={'targ':'#19342d','baseline':'#b0a48a','new':'#6f8f3a'}; L={'targ':'Targ (EN, 10/10)','baseline':'UA baseline (7–8)','new':'UA новая (8–9)'}
plt.rcParams.update({'font.family':'DejaVu Sans','font.size':11,'axes.spines.top':False,'axes.spines.right':False,'figure.facecolor':'white'})
def save(fig,name):
    fig.tight_layout(); fig.savefig(F/f'{name}.svg'); fig.savefig(F/f'{name}.png',dpi=140); plt.close(fig)
# F1 block budget: seconds and syl/s
BL=['setup','mentor','care','change','return','selfworth','cta','tail']; BLR={'setup':'завязка','mentor':'наставница','care':'уход','change':'результат','return':'встреча 2','selfworth':'своё мнение','cta':'CTA','tail':'хвост'}
fig,ax=plt.subplots(1,2,figsize=(12,4.2)); x=np.arange(len(BL)); w=0.27
for i,k in enumerate(['targ','baseline','new']):
    rows={b['id']:b for b in blocks[k]}
    ax[0].bar(x+(i-1)*w,[rows[b]['seconds'] for b in BL],w,color=C[k],label=L[k])
    ax[1].bar(x+(i-1)*w,[rows[b]['sylPerSec'] or 0 for b in BL],w,color=C[k],label=L[k])
for a,t in zip(ax,['Секунды на блок','Слогов в секунду внутри блока']):
    a.set_xticks(x); a.set_xticklabels([BLR[b] for b in BL],rotation=20); a.set_title(t,loc='left')
ax[0].legend(frameon=False,fontsize=9); save(fig,'f1-blocks')
# F2 word length + phrase endings
fig,ax=plt.subplots(1,2,figsize=(12,4.2))
for i,k in enumerate(['targ','baseline','new']):
    r=text[k]; ax[0].bar(np.arange(3)+(i-1)*w,[r['monosyllableShare'],r['poly3Share'],r['poly4Share']],w,color=C[k],label=L[k])
ax[0].set_xticks(range(3)); ax[0].set_xticklabels(['1 слог','≥3 слогов','≥4 слогов']); ax[0].set_title('Доля слов по длине',loc='left'); ax[0].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)); ax[0].legend(frameon=False,fontsize=9)
cats=['vowel','consonant','plosive']; catl={'vowel':'гласная','consonant':'согласная','plosive':'смычная (p/t/k…)'}
for i,k in enumerate(['targ','baseline','new']):
    fe=text[k]['phraseFinalEnding']; vals=[fe.get('vowel',0),fe.get('consonant',0)+fe.get('consonant_silent_e',0),fe.get('plosive',0)]
    ax[1].bar(np.arange(3)+(i-1)*w,vals,w,color=C[k])
ax[1].set_xticks(range(3)); ax[1].set_xticklabels([catl[c] for c in cats]); ax[1].set_title('Чем заканчивается последнее слово фразы',loc='left'); ax[1].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)); save(fig,'f2-words')
# F3 syllable rate per phrase over normalized story time (block-relative)
fig,ax=plt.subplots(figsize=(12,4))
for k in ['targ','baseline','new']:
    ph=text[k]['phrasesList']; d=text[k]['duration']
    xs=[p['t']/d*100 for p in ph if p['e']-p['t']>0.3]; ys=[p['syl']/(p['e']-p['t']) for p in ph if p['e']-p['t']>0.3]
    ys=np.clip(ys,0,8); ax.plot(xs,ys,'-',color=C[k],alpha=.85,lw=1.4,label=L[k])
ax.set_xlabel('Позиция в песне, % длительности'); ax.set_ylabel('слог/с во фразе'); ax.set_title('Скорость подачи по фразам: где песня спешит и где даёт слову место',loc='left'); ax.legend(frameon=False,fontsize=9); save(fig,'f3-rate')
# F4 sustained notes + intervals
fig,ax=plt.subplots(1,2,figsize=(12,4.2))
for i,k in enumerate(['targ','baseline','new']):
    z=np.load(S/'traces'/f'{k}.npz'); d=z['notes_d']; bins=[0.08,0.15,0.25,0.4,0.6,1.0]
    h,_=np.histogram(d,bins=bins); ax[0].bar(np.arange(len(h))+(i-1)*w,h/len(d),w,color=C[k],label=L[k])
ax[0].set_xticks(range(5)); ax[0].set_xticklabels(['80–150 мс','150–250','250–400','400–600','>600 мс']); ax[0].set_title('Длительность нот (pYIN, отделённый вокал)',loc='left'); ax[0].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)); ax[0].legend(frameon=False,fontsize=9)
keys=['repeat(<0.75st)','step(0.75-2.5)','third(2.5-4.5)','leap(>=4.5)']; kl=['повтор тона','секунда','терция','скачок ≥ кварты']
for i,k in enumerate(['targ','baseline','new']):
    ax[1].bar(np.arange(4)+(i-1)*w,[audio[k]['notes']['intervalHist'][q] for q in keys],w,color=C[k])
ax[1].set_xticks(range(4)); ax[1].set_xticklabels(kl); ax[1].set_title('Интервалы между соседними нотами',loc='left'); ax[1].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)); save(fig,'f4-notes')
# F5 vocal vs music per block + centroid
fig,ax=plt.subplots(1,2,figsize=(12,4.2)); BL7=BL[:7]
for i,k in enumerate(['targ','baseline','new']):
    rows={b['id']:b for b in audio[k]['blocks']}
    ax[0].bar(x[:7]+(i-1)*w,[rows[b]['vocMinusMusic'] for b in BL7],w,color=C[k],label=L[k]); ax[1].bar(x[:7]+(i-1)*w,[rows[b]['centroidHz'] for b in BL7],w,color=C[k])
ax[0].axhline(0,color='#999',lw=.8); ax[0].set_xticks(x[:7]); ax[0].set_xticklabels([BLR[b] for b in BL7],rotation=20); ax[0].set_title('Вокал минус музыка, dB (стемы Demucs)',loc='left'); ax[0].legend(frameon=False,fontsize=9)
ax[1].set_xticks(x[:7]); ax[1].set_xticklabels([BLR[b] for b in BL7],rotation=20); ax[1].set_title('Спектральный центроид вокала, Гц (яркость)',loc='left'); ax[1].set_ylim(2500,4500); save(fig,'f5-mix')
# F6 matched moments pitch contours
PAIRS=[('«That week at my daughter\'s dance pickup» / «Того тижня з танців доньку забирала»',('targ',79.5,83.5),('new',74.3,78.6)),
 ('«What do you use? Your skin is a dream» / «Питаю: Чим ти користуєшся?»',('targ',90.0,94.8),('new',86.0,90.5)),
 ('«Stress will do that ×3» / «Стрес лишає слід ×3»',('targ',27.2,33.2),('new',23.1,32.2)),
 ('«Brighter by week six, I was in shock» / «А за шість — не повірила!»',('targ',132.8,137.9),('new',135.0,140.5)),
 ('«Not pity, not sympathy, just confused» / «Не жалість. Не співчуття. Розгублена»',('targ',156.0,159.7),('new',158.3,163.5)),
 ('«Not because her opinion mattered, but because mine finally did» / «Не тому, що її думка важлива. А тому, що свою я нарешті ціную»',('targ',175.9,181.7),('new',181.8,187.5))]
fig,axes=plt.subplots(3,2,figsize=(13,10))
for ax,(title,ta,nb) in zip(axes.flat,PAIRS):
    for (k,a,b),ls in zip((ta,nb),('-','-')):
        z=np.load(S/'traces'/f'{k}.npz'); t=z['t']; m=z['midi']; g=z['good']; sel=(t>=a)&(t<=b)
        tt=t[sel]-a; mm=np.where(g[sel],m[sel],np.nan); ax.plot(tt,mm,ls,color=C[k],lw=1.6,label=L[k])
        vd=z['vdb'][sel]; ax.fill_between(tt,50,50+np.clip((vd-vd.max()+40)/40,0,1)*3,color=C[k],alpha=.15,lw=0)
    ax.set_title(title,loc='left',fontsize=9); ax.set_ylim(50,76); ax.set_ylabel('MIDI'); ax.set_xlabel('с от начала фрагмента')
axes.flat[0].legend(frameon=False,fontsize=8); save(fig,'f6-moments')
# F7 loudness short-term over time
fig,ax=plt.subplots(figsize=(12,3.6))
for k in ['targ','baseline','new']:
    z=np.load(S/'traces'/f'{k}.npz'); t=z['t']; v=z['vdb']; m=z['mdb']
    # 2s moving average of music level
    w2=int(2/(t[1]-t[0])); mm=np.convolve(m,np.ones(w2)/w2,'same'); ax.plot(t/t[-1]*100,mm-np.median(mm),color=C[k],lw=1.2,label=L[k])
ax.set_xlabel('Позиция в песне, %'); ax.set_ylabel('музыка, dB отн. медианы'); ax.set_title('Как дышит аккомпанемент: уровень музыки (стемы без вокала), сглажено 2 с',loc='left'); ax.legend(frameon=False,fontsize=9); save(fig,'f7-music')
print('figures ok')
