from pathlib import Path
import shutil, json, csv, re, subprocess, sys
import img2pdf

ROOT=Path('/home/agent/family/Lernen/Pruefungen_Emilia_4_Klasse')
RAW=ROOT/'_raw_google_drive'
WORK=Path('/home/agent/tmp/emilia_pruefungen_import')
PRE=WORK/'preprocessed_jpg'
DOCT=WORK/'docling_text'
TESST=WORK/'tesseract_text'
OUT=ROOT

# Preliminary grouping based on OCR + sequential filenames. No LLM vision used.
GROUPS=[
 {'subject':'Englisch','slug':'Double_Decker_Level2_Unit8_Transport','title':'Double Decker Level 2 – Unit 8 – Transport','pages':[4419,4420,4421], 'topics':['transport','listening','reading','writing','Eagle invention']},
 {'subject':'Englisch','slug':'Vocabulary_Comparative_Adjectives','title':'Vocabulary & Comparative Adjectives','pages':[4422], 'topics':['vocabulary','comparative adjectives','picture dictionary']},
 {'subject':'Englisch','slug':'Poems_Rubric','title':'Poems – Bewertungsraster / Vortrag','pages':[4423], 'topics':['poem recitation','speaking','rubric']},
 {'subject':'Englisch','slug':'Double_Decker_Level2_Unit3_4_Sports_Routines_Internet','title':'Double Decker Level 2 – Units 3/4 – Sports, Routines, Internet','pages':[4424,4425,4426,4427,4428,4429,4430,4431,4432], 'topics':['sports','daily routines','internet safety','listening','reading','writing']},
 {'subject':'Englisch','slug':'Numbers_Mini_Test','title':'Numbers Mini-test','pages':[4433], 'topics':['numbers','spelling numbers']},
 {'subject':'Englisch','slug':'Double_Decker_Level2_Unit2_Daily_Routines','title':'Double Decker Level 2 – Unit 2 – Daily Routines','pages':[4434,4437,4438,4439,4440,4441], 'topics':['daily routines','time','listening','reading','writing','vocabulary']},

 {'subject':'Mathe','slug':'Geometrie_Bauplaene_Massstab_Symmetrie','title':'Geometrie – Baupläne, Massstab, Symmetrie','pages':[4443,4444,4445,4446], 'topics':['Bauplan','Massstab','Symmetrie','Seitenansichten']},
 {'subject':'Mathe','slug':'Schriftliche_Division_Monsterzahl','title':'Schriftliche Division – Rechenprotokoll / Monsterzahl','pages':[4447,4448,4449,4450], 'topics':['schriftliche Division','Division mit Rest','Textaufgabe','Monsterzahl']},
 {'subject':'Mathe','slug':'LZK_4_8_Gewichte_Hohlmasse','title':'LZK 4.8 – Gewichte / Hohlmasse','pages':[4451,4452,4453], 'topics':['Gewichte','kg','g','t','Hohlmasse','ml','cl','l','Textaufgaben']},
 {'subject':'Mathe','slug':'LZK_4_4_Geometrie_Flaechen_Parallel_Senkrecht','title':'LZK 4.4 – Geometrie / Flächen / parallel-senkrecht','pages':[4454,4455,4456,4457], 'topics':['Flächeninhalt','Umfang','parallel','senkrecht','Geodreieck','Holzwürfel']},
 {'subject':'Mathe','slug':'Textaufgaben_Schriftliche_Multiplikation','title':'Textaufgaben / Schriftliche Multiplikation','pages':[4458,4459,4460,4461], 'topics':['schriftliche Multiplikation','Textaufgaben','Rechenprotokoll','fehlende Ziffern']},
 {'subject':'Mathe','slug':'Mehr_als_1000_Tausender','title':'Mehr als 1000 / Tausender','pages':[4462,4463,4464,4465], 'topics':['Stellenwert','Tausender','Zahlen schreiben','Zahlenrätsel']},
 {'subject':'Mathe','slug':'LZK_4_2_Zahlen_Stellenwert','title':'MATHE LZK 4.2 – Zahlen / Stellenwert','pages':[4466,4467,4468], 'topics':['Stellenwert','Zahlen bilden','Zahlen ordnen','Zehntausender','Hunderttausender']},
 {'subject':'Mathe','slug':'Zahlenstrahl_Zahlen_ordnen','title':'Zahlenstrahl / Zahlen ordnen','pages':[4469,4470,4471], 'topics':['Zahlenstrahl','Zahlen ordnen','Vergleichszeichen','Teilbarkeit']},
 {'subject':'Mathe','slug':'MATHE_LZK_4_3_Laengen_Zeit','title':'MATHE LZK 4.3 – Längen / Zeit','pages':[4472,4473,4474], 'topics':['Längen','Zeit','m','cm','mm','km','min','s','Textaufgaben']},
 {'subject':'Mathe','slug':'LZK_4_8_Rechnen_Addition_Subtraktion','title':'LZK 4.8 – Rechnen / Addition / Subtraktion','pages':[4475,4476,4477], 'topics':['Addition','Subtraktion','Zahlenturm','Zahlenrätsel','Fachbegriffe']},
 {'subject':'Mathe','slug':'Rechnen_Division_Multiplikation_Grosse_Zahlen','title':'Rechnen – Division / Multiplikation / grosse Zahlen','pages':[4478,4479], 'topics':['Division','Multiplikation','Rechenzeichen','fehlende Zahlen']},

 {'subject':'NMG','slug':'Beurteilungsraster_NMG','title':'Beurteilungsraster NMG','pages':[4482], 'topics':['Beurteilungsraster','NMG']},
 {'subject':'Deutsch','slug':'Leseverstaendnis_Das_Kartenspiel','title':'Übungen zum Leseverständnis – Das Kartenspiel','pages':[4483], 'topics':['Leseverständnis','Das Kartenspiel']},
 {'subject':'Deutsch','slug':'Adjektive','title':'Adjektive','pages':[4484,4485], 'topics':['Adjektive','Gegenteil','Nomen-Adjektiv-Verbindungen']},
 {'subject':'NMG','slug':'Praesentation_Tiere','title':'Präsentation Tiere','pages':[4486,4487], 'topics':['Tierpräsentation','Vortrag','Bewertungskriterien']},
 {'subject':'NMG','slug':'NMG_Pruefung_Auge_und_Ohr','title':'NMG-Prüfung – Auge und Ohr','pages':[4488,4489,4490,4491,4492], 'topics':['Auge','Ohr','Schall','Wind','Schallwellen','Sinnesorgane']},
 {'subject':'NMG','slug':'NMG_Pruefung_Energie','title':'NMG-Prüfung – Energie','pages':[4493,4494,4495,4496,4497], 'topics':['Energieformen','Energieumwandlung','Wärmeenergie','elektrische Energie','Bewegungsenergie']},
 {'subject':'NMG','slug':'NMG_Pruefung_Wetter_und_Wolken','title':'NMG-Prüfung – Wetter und Wolken','pages':[4498,4499,4500,4501,4502,4503], 'topics':['Wetter','Wolken','Wetterinstrumente','Klimadiagramm','Wolkenentstehung']},
 {'subject':'Deutsch','slug':'Lesefluessigkeit_Brillen','title':'Beurteilung DE – Leseflüssigkeit – Brillen','pages':[4505], 'topics':['Leseflüssigkeit','Brillen','Vorlesen']},
 {'subject':'Deutsch','slug':'Pruefung_Nomen_erkennen_grossschreiben','title':'Prüfung – Nomen erkennen und grossschreiben','pages':[4506], 'topics':['Nomen','Grossschreibung','zusammengesetzte Nomen']},
 {'subject':'Deutsch','slug':'Test_Praesens_Verben','title':'Test – Präsens / Verben','pages':[4507,4508], 'topics':['Präsens','Verben','Personalformen','Verbzusätze']},
 {'subject':'Deutsch','slug':'Leseverstaendnis_Auf_goldener_Tauchtour','title':'Leseverständnis – Auf goldener Tauchtour','pages':[4509,4510,4511,4512], 'topics':['Leseverständnis','Auf goldener Tauchtour','Lesespur']},
 {'subject':'Deutsch','slug':'Pruefung_Nomen_und_Verben','title':'Prüfung – Nomen und Verben','pages':[4513,4514], 'topics':['Nomen','Verben','Grundform','Personalform','Verbzusätze']},
]

num_to_raw={int(re.search(r'IMG_(\d+)',p.name,re.I).group(1)):p for p in RAW.iterdir() if p.is_file() and re.search(r'IMG_(\d+)',p.name,re.I)}

all_rows=[]
created=[]
for idx,g in enumerate(GROUPS, start=1):
    subject_dir=OUT/g['subject']
    exam_dir=subject_dir/g['slug']
    photos_dir=exam_dir/'Fotos_Original'
    jpg_dir=exam_dir/'Seiten_JPG'
    ocr_dir=exam_dir/'OCR'
    for d in [photos_dir,jpg_dir,ocr_dir]: d.mkdir(parents=True, exist_ok=True)
    jpgs=[]
    page_rows=[]
    for i,num in enumerate(g['pages'], start=1):
        src=num_to_raw.get(num)
        if not src:
            print('WARN missing raw',num)
            continue
        raw_target=photos_dir/src.name
        if not raw_target.exists() or raw_target.stat().st_size != src.stat().st_size:
            shutil.copy2(src, raw_target)
        pre=PRE/f'IMG_{num}.jpg'
        if not pre.exists():
            # create if batch did not create it
            subprocess.run(['convert',str(src),'-auto-orient','-resize','1800x1800',str(pre)], check=True)
        jpg_target=jpg_dir/f'{i:02d}_IMG_{num}.jpg'
        if not jpg_target.exists() or jpg_target.stat().st_size != pre.stat().st_size:
            shutil.copy2(pre, jpg_target)
        jpgs.append(jpg_target)
        dt=DOCT/f'IMG_{num}.txt'; tt=TESST/f'IMG_{num}.txt'
        docling=dt.read_text(errors='ignore') if dt.exists() else ''
        tess=tt.read_text(errors='ignore') if tt.exists() else ''
        (ocr_dir/f'{i:02d}_IMG_{num}_docling.txt').write_text(docling, encoding='utf-8')
        (ocr_dir/f'{i:02d}_IMG_{num}_tesseract.txt').write_text(tess, encoding='utf-8')
        page_rows.append({'page':i,'image':src.name,'docling_chars':len(docling.strip()),'tesseract_chars':len(tess.strip())})
        all_rows.append({'subject':g['subject'],'exam_slug':g['slug'],'exam_title':g['title'],'page':i,'image':src.name,'topics':'; '.join(g['topics']),'docling_chars':len(docling.strip()),'tesseract_chars':len(tess.strip())})
    pdf_path=exam_dir/f"{g['subject']}_Emilia_4Kl_{g['slug']}.pdf"
    if jpgs:
        with open(pdf_path,'wb') as f:
            f.write(img2pdf.convert([str(p) for p in jpgs], rotation=img2pdf.Rotation.ifvalid))
    index_text=[f"# {g['title']}", '', f"- Fach: {g['subject']}", f"- Seiten/Fotos: {len(jpgs)}", f"- PDF: `{pdf_path.name}`", f"- Status: ausgefüllte Originalprüfung, nicht bereinigt", f"- Themen: {', '.join(g['topics'])}", '', '## Seiten', '']
    for pr in page_rows:
        index_text.append(f"- Seite {pr['page']}: `{pr['image']}` — OCR Docling {pr['docling_chars']} Zeichen, Tesseract {pr['tesseract_chars']} Zeichen")
    (exam_dir/'README.md').write_text('\n'.join(index_text)+'\n', encoding='utf-8')
    (exam_dir/'metadata.json').write_text(json.dumps({**g,'pdf':str(pdf_path),'pages_detail':page_rows}, ensure_ascii=False, indent=2), encoding='utf-8')
    created.append({'subject':g['subject'],'slug':g['slug'],'title':g['title'],'pages':len(jpgs),'pdf':str(pdf_path)})

# global inventory
OUT.mkdir(parents=True, exist_ok=True)
with open(OUT/'00_Pruefungsseiten_Inventar.csv','w',newline='',encoding='utf-8') as f:
    w=csv.DictWriter(f, fieldnames=['subject','exam_slug','exam_title','page','image','topics','docling_chars','tesseract_chars'])
    w.writeheader(); w.writerows(all_rows)
(OUT/'00_Pruefungen_Inventar.json').write_text(json.dumps(created,ensure_ascii=False,indent=2),encoding='utf-8')

# searchable markdown index
lines=['# Prüfungen Emilia 4. Klasse – Index', '', 'Status: ausgefüllte Originalprüfungen; keine Bereinigung der Antworten/Korrekturen.', '', '## Prüfungen', '']
for c in created:
    rel=Path(c['pdf']).relative_to(OUT)
    lines.append(f"- **{c['subject']}** — {c['title']} ({c['pages']} Seiten) — `{rel}`")
lines += ['', '## Hinweis OCR', 'Docling+Tesseract und Tesseract-Fallback wurden pro Seite gespeichert. Für semantische Feinprüfung/Bereinigung später Vision sparsam einsetzen.']
(OUT/'README.md').write_text('\n'.join(lines)+'\n',encoding='utf-8')
print('created_exams',len(created),'pages_indexed',len(all_rows))
for c in created:
    print(c['subject'], c['pages'], c['slug'])
