#!/usr/bin/env python3
"""SkyZ Files: automatische echte Dokumentordner. sudo python3 DATEI.py"""
import ast,base64,datetime,json,os,shutil,sqlite3,subprocess,tempfile,zlib
from pathlib import Path
ROOT=Path('/data/skyzfiles')
PAYLOAD='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'

MODEL='''
class FolderAssignment(models.Model):
    document = models.OneToOneField(Document, on_delete=models.CASCADE, related_name='folder_assignment')
    mode = models.CharField(max_length=20, default='auto')
    assigned_folder = models.CharField(max_length=900, blank=True)
    evaluated_sha = models.CharField(max_length=64, blank=True)
    note = models.CharField(max_length=500, blank=True)
'''

def replace_once(text,old,new):
    if text.count(old)!=1:raise RuntimeError('Unbekannte Codeversion; Abbruch bei: '+old[:90])
    return text.replace(old,new,1)

def patch_files(app,assets):
    changes={}
    def read(p):return (app/p).read_text()
    models=read('vault/models.py')
    if 'class FolderAssignment(' not in models:models+='\n'+MODEL
    changes['vault/models.py']=models
    classify=read('vault/classify.py')
    if "('Berufsschule', 'Bildung'" not in classify:
        anchor=" ('Gehaltsabrechnung', 'Arbeit',"
        classify=replace_once(classify,anchor," ('Schulzeugnis', 'Bildung', ['schulzeugnis', 'berufsschulzeugnis', 'jahreszeugnis', 'abschlusszeugnis']),\n ('Berufsschule', 'Bildung', ['berufsschule', 'berufsschul', 'lernfeld', 'blockunterricht', 'unterrichtsmaterial', 'klassenarbeit']),\n ('Ausbildung', 'Bildung', ['ausbildungsvertrag', 'ausbildungsnachweis', 'berichtsheft', 'ihk-prüfung', 'ihk prüfung']),\n"+anchor)
    changes['vault/classify.py']=classify
    worker=read('vault/worker.py')
    if 'from .routing import recover_pending_moves' not in worker:
        worker=replace_once(worker,'from .search import index_document','from .search import index_document\nfrom .routing import recover_pending_moves,route_pending,mark_manual_on_move,queue')
        worker=replace_once(worker,'doc = candidate; doc.path = relative','doc = candidate; mark_manual_on_move(doc,relative); doc.path = relative')
        worker=replace_once(worker,'def run_cycle():\n    reconcile()','def run_cycle():\n    recover_pending_moves()\n    reconcile()')
        worker=replace_once(worker,'        enhance(doc)','        enhance(doc)\n        queue(doc)\n    route_pending()')
    changes['vault/worker.py']=worker
    views=read('vault/views.py')
    if 'from .routing import routing_info' not in views:
        views=replace_once(views,'from .worker import ingest, audit','from .worker import ingest, audit\nfrom .routing import routing_info,queue,mark_manual_on_move')
        views=replace_once(views,"    snippets = {}","""    folder = request.GET.get('folder','')
    if folder == '/': qs = qs.exclude(path__contains='/')
    elif folder:
        try:
            if len(folder)>900: raise ValueError()
            safe_path(folder+'/placeholder')
            qs = qs.filter(path__startswith=folder.rstrip('/')+'/')
        except ValueError: return problem('Ungültiger Ordnerfilter.')
    snippets = {}""")
        views=replace_once(views,"doc.save(); index_document(doc); audit('metadata',doc)","doc.save(); index_document(doc); audit('metadata',doc); queue(doc)")
        views=replace_once(views,"    info['notes'] = doc.notes","    info['notes'] = doc.notes\n    info['folder_routing'] = routing_info(doc)")
        views=replace_once(views,'os.link(path,target); path.unlink()','os.link(path,target); path.unlink(); mark_manual_on_move(doc,relative)')
    changes['vault/views.py']=views
    urls=read('config/urls.py')
    if 'from vault import folder_views' not in urls:
        urls=replace_once(urls,'from vault import views','from vault import views\nfrom vault import folder_views')
        urls=replace_once(urls,'urlpatterns=[',"urlpatterns=[\n path('api/folders',folder_views.folders),\n path('api/folders/preview',folder_views.preview),\n path('api/folders/apply',folder_views.apply),\n path('api/documents/<uuid:ident>/folder-routing',folder_views.toggle_document),")
    changes['config/urls.py']=urls
    js=read('static/app.js')
    if 'folderRoutingToggle' not in js:
        js=replace_once(js,"sort:'newest',page:1", "sort:'newest',folder:'',page:1")
        js=replace_once(js,'state.q||state.type||state.tag||state.min||state.max','state.q||state.type||state.tag||state.min||state.max||state.folder')
        js=replace_once(js,"['q','tag','type','min','max']", "['q','tag','type','min','max','folder']")
        js=replace_once(js,"['#searchInput','#typeFilter','#minAmount','#maxAmount']", "['#searchInput','#typeFilter','#minAmount','#maxAmount','#folderFilter']")
        js=replace_once(js,' <h3>Automatische Zuordnung</h3>', ''' <h3>Ordnerzuordnung</h3><p class="small muted folder-routing-note">${esc(d.folder_routing?.note||'Neue Eingänge werden nach der Texterkennung einsortiert.')}<br>Vorschlag: ${esc(d.folder_routing?.suggested_folder||'Unsortiert')}</p>${!d.deleted?`<button class="secondary" id="folderRoutingToggle">${d.folder_routing?.mode==='auto'?'Ordner festhalten':'Automatisch zuordnen'}</button>`:''}
 <h3>Automatische Zuordnung</h3>''')
        js=replace_once(js,' renderPreview();', ''' $('#folderRoutingToggle')?.addEventListener('click',async()=>{const enabled=d.folder_routing?.mode!=='auto';if(enabled&&!await ask('Automatische Ordnerzuordnung aktivieren?','Dieses Dokument darf nach seinem Typ in den vorgeschlagenen Ordner verschoben werden. Die Änderung wird auch per SFTP übernommen.','Aktivieren'))return;try{await api('/api/documents/'+d.id+'/folder-routing',{method:'POST',body:{enabled,sha256:d.sha256}});await openDocument(d.id);toast(enabled?'Ordnerzuordnung vorgemerkt.':'Ordner bleibt erhalten.')}catch(e){toast(e.message)}});
 renderPreview();''')
    changes['static/app.js']=js
    html=read('templates/app.html')
    if 'id="foldersDialog"' not in html:
        html=replace_once(html,'</head>', '<link rel="stylesheet" href="{% static \'folders.css\' %}"><script src="{% static \'folders.js\' %}" defer></script></head>')
        html=replace_once(html,'<button class="filterbutton" id="amountToggle">','<label class="sr-only" for="folderFilter">Ordner</label><select id="folderFilter"><option value="">Alle Ordner</option></select><button class="filterbutton" id="amountToggle">')
        html=replace_once(html,'<h3>Verarbeitung</h3>','<button class="secondary" id="foldersOpen" type="button">Automatische Ordner</button><h3>Verarbeitung</h3>')
        html=replace_once(html,'</body>', '''<dialog id="foldersDialog" class="compact-dialog"><div class="dialog-heading"><h2>Automatische Ordner</h2><button class="iconbutton" id="closeFolders" type="button" aria-label="Schließen">×</button></div><div class="dialog-body"><p><label><input id="folderAutoEnabled" type="checkbox"> Neue Eingänge automatisch einsortieren</label></p><p class="muted">Die Ordner liegen in der SFTP-Ablage. Manuell gewählte Ordner bleiben geschützt. Unklare Dokumente kommen nach Unsortiert. Bei ausgeschalteter Automatik bleiben vorgemerkte Zuordnungen pausiert.</p><details><summary>Ordner nach Dokumenttyp</summary><pre id="folderRules"></pre></details><h3>Vorhandene Dokumente</h3><p class="muted">Vorschau für bis zu 20 Änderungen. SFTP-Abgleich vor dem Übernehmen pausieren; viele Verschiebungen können dessen Löschgrenze auslösen.</p><div class="actions"><button class="secondary" id="previewFolders" type="button">Zuordnung vorschlagen</button><button class="primary" id="applyFolders" type="button" disabled>Gezeigte Zuordnung übernehmen</button></div><p id="folderPlanStatus" role="status"></p><div id="folderPlan"></div></div></dialog></body>''')
    changes['templates/app.html']=html
    changes.update(assets)
    for name,text in changes.items():
        target=app/name
        if target.is_symlink():raise RuntimeError('Unerwarteter Symlink: '+name)
        if name.endswith('.py'):ast.parse(text)
    return changes

def atomic_write(p,data):
    fd,name=tempfile.mkstemp(prefix='.folders-update-',dir=p.parent)
    try:
        with os.fdopen(fd,'wb') as f:f.write(data);f.flush();os.fsync(f.fileno())
        os.chmod(name,0o644);os.replace(name,p)
    finally:Path(name).unlink(missing_ok=True)

def main():
    if os.geteuid()!=0:raise SystemExit('Bitte sudo python3 verwenden.')
    os.umask(0o022);app=ROOT/'app';python=ROOT/'venv/bin/python';db=ROOT/'state/db.sqlite3'
    if not python.is_file() or not db.is_file() or db.is_symlink():raise SystemExit('Vorhandene SkyZ-Installation unter /data/skyzfiles fehlt.')
    migrations={p.name for p in (app/'vault/migrations').glob('*.py')}
    if migrations-{'__init__.py','0001_initial.py','0002_folder_assignment.py'}:raise SystemExit('Zusätzliche Datenbankmigrationen gefunden; Version zuerst prüfen.')
    assets=json.loads(zlib.decompress(base64.b64decode(PAYLOAD)))
    changes=patch_files(app,assets)
    backup=ROOT/'config'/('folders-backup-'+datetime.datetime.now().strftime('%Y%m%d-%H%M%S-%f'));backup.mkdir(mode=0o700)
    originals={name:(app/name).read_bytes() if (app/name).exists() else None for name in changes}
    for name,data in originals.items():
        if data is not None:
            dest=backup/name;dest.parent.mkdir(parents=True,exist_ok=True);shutil.copy2(app/name,dest)
    active=[s for s in ['skyzfiles-web','skyzfiles-worker','skyzfiles-sftp'] if subprocess.run(['systemctl','is-active','--quiet',s]).returncode==0]
    manage=['runuser','-u','skyzfiles','--',str(python),str(app/'manage.py')]
    saved_db=False
    try:
        if active:
            print('Dienste werden für die Datenbanksicherung und Aktualisierung kurz gestoppt.',flush=True)
            subprocess.run(['systemctl','stop',*active],check=True)
        with sqlite3.connect(db) as source,sqlite3.connect(backup/'db.sqlite3') as dest:source.backup(dest)
        saved_db=True
        for name,text in changes.items():atomic_write(app/name,text.encode())
        subprocess.run(manage+['check'],check=True)
        subprocess.run(manage+['migrate','--noinput'],check=True)
        subprocess.run(manage+['collectstatic','--noinput'],check=True)
    except Exception:
        if saved_db:
            for name,data in originals.items():
                if data is None:(app/name).unlink(missing_ok=True)
                else:shutil.copy2(backup/name,app/name)
            with sqlite3.connect(backup/'db.sqlite3') as source,sqlite3.connect(db) as dest:source.backup(dest)
            subprocess.run(manage+['collectstatic','--noinput'],check=False)
            print('Update fehlgeschlagen; Code und Datenbank wiederhergestellt. Sicherung:',backup)
        raise
    finally:
        if active:subprocess.run(['systemctl','start',*active],check=True)
    print('Automatische Ordner installiert. Sicherung:',backup)
    print('WebApp neu laden. Bestehende Dokumente: Einstellungen → Automatische Ordner → Zuordnung vorschlagen.')
    print('Neue Dateien in Eingang, Scans oder direkt in /files werden nach der OCR einsortiert.')

if __name__=='__main__':main()
