#!/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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'

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):
    if not (app/'vault/shares.py').exists():raise RuntimeError('Bitte zuerst das Ordner-Freigaben-Update installieren.')
    changes=dict(assets);dialog=changes.pop('_dialog')
    html=(app/'templates/app.html').read_text()
    js=(app/'static/app.js').read_text()
    if 'id="shareDialog"' not in html:
        html=replace_once(html,'<a class="navitem" href="/folders/"><svg><use href="#i-file"/></svg><span>Ordner</span></a>', '<button class="navitem" data-state="folders"><svg><use href="#i-folder"/></svg><span>Ordner</span></button>')
        html=replace_once(html,'<a class="navitem" href="/shares/"><svg><use href="#i-arrow"/></svg><span>Freigaben</span></a>', '<button class="navitem" data-state="shares"><svg><use href="#i-link"/></svg><span>Freigaben</span></button>')
        html=replace_once(html,'</head>', '<link rel="stylesheet" href="{% static \'integrated.css\' %}"><script src="{% static \'integrated.js\' %}" defer></script></head>')
        html=replace_once(html,'</defs>', '<symbol id="i-folder" viewBox="0 0 24 24"><path d="M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7zM3 9h18"/></symbol><symbol id="i-link" viewBox="0 0 24 24"><path d="m10 13 4-4m-6 7-2 2a4 4 0 0 1-6-6l5-5a4 4 0 0 1 6 0m2 2 2-2a4 4 0 0 1 6 6l-5 5a4 4 0 0 1-6 0" transform="translate(1 0)"/></symbol></defs>')
        html=replace_once(html,'   <div class="searchbar">','''   <div id="folderBrowserPanel" hidden><div class="folder-location"><nav class="folder-crumbs" id="folderCrumbs" aria-label="Ordnerpfad"></nav><button class="quiet" id="folderParent" type="button">↑ Zurück</button></div><div class="documents-panel folder-panel"><div class="listheading folder-heading"><span id="folderCount">Unterordner</span><span>Dateien</span><span></span></div><div id="folderEntries"></div></div><p id="folderBrowseNote" class="folder-note" hidden></p></div>
   <div class="searchbar">''')
        html=replace_once(html,'   <div class="documents-panel" id="dropzone">','''   <div id="sharesPanel" hidden><div class="actions shares-actions"><button class="secondary" id="refreshShares" type="button">Aktualisieren</button><span class="muted small">Zum Teilen ein Dokument öffnen und „Link teilen“ wählen.</span></div><div class="documents-panel"><div class="listheading share-list-heading"><span id="shareResultLabel">Freigaben</span><span>Gültigkeit / Schutz</span><span>Status</span></div><div id="shareEntries" aria-live="polite"></div></div><p id="shareLimitNote" class="small muted share-view-note" hidden>Es werden die neuesten 200 Freigaben angezeigt.</p><p class="footnote share-view-note">Wähle eine Freigabe, um Gültigkeit, Downloadlimit und Passwort zu bearbeiten.</p></div>
   <div class="documents-panel" id="dropzone">''')
        html=replace_once(html,'</body>',dialog+'</body>')
    changes['templates/app.html']=html
    if 'window.SkyzSpaces' not in js:
        js=replace_once(js,"async function loadDocuments(){\n const seq=++listSequence;const params=new URLSearchParams({...state,state:state.view});params.delete('view');", """async function loadDocuments(){
 const seq=++listSequence;if(state.view==='shares')return window.SkyzSpaces?.loadShares();
 const params=new URLSearchParams({...state,state:state.view});params.delete('view');
 if(state.view==='folders'){params.set('state','');params.set('folder',window.SkyzSpaces?.folderPath||'/');params.set('folder_scope','direct');window.SkyzSpaces?.refreshFolders()}""")
        js=replace_once(js,"function changeView(view){state.view=view;state.page=1;state.tag='';", "function changeView(view){state.view=view;state.page=1;state.tag='';++listSequence;window.SkyzSpaces?.activate(view);")
        js=replace_once(js,"trash:'Papierkorb'};", "trash:'Papierkorb',folders:'Deine Ordner',shares:'Deine Freigaben'};")
        js=replace_once(js,'<a class="secondary" href="/shares/?document=${d.id}">Link teilen</a>', '<button class="secondary" type="button" data-share-document="${d.id}">${icon(\'link\')}Link teilen</button>')
        js=replace_once(js,"if(b){state.tag=b.dataset.tag;", "if(b){if(state.view==='shares')changeView('');state.tag=b.dataset.tag;")
        js=replace_once(js,"state.q||state.type||state.tag?'Keine passenden Dokumente.':state.view==='trash'", "state.q||state.type||state.tag?'Keine passenden Dokumente.':state.view==='folders'?'Dieser Ordner ist noch leer.':state.view==='trash'")
        js=replace_once(js,"'Lade Dokumente hoch oder scanne die erste Seite mit deiner Kamera.'", "state.view==='folders'?'Hier erscheinen die direkt enthaltenen Dokumente nach dem Import.':'Lade Dokumente hoch oder scanne die erste Seite mit deiner Kamera.'")
        js=replace_once(js,'\nconst deepLinkDocument=new URLSearchParams(location.search).get("document");\nif(deepLinkDocument&&/^[0-9a-fA-F-]{36}$/.test(deepLinkDocument))openDocument(deepLinkDocument);','')
    js=js.replace("state.view==='folders'?'Dieser Ordner ist noch leer.'", "state.view==='folders'?'Keine Dateien direkt in diesem Ordner.'")
    changes['static/app.js']=js
    urls=(app/'config/urls.py').read_text()
    urls=urls.replace("path('folders/',folder_browser.page)","path('folders/',views.app)").replace("path('shares/',shares.manager)","path('shares/',views.app)")
    changes['config/urls.py']=urls
    views=(app/'vault/views.py').read_text()
    if "request.GET.get('folder_scope') == 'direct'" not in views:
        views=replace_once(views,'from django.db.models import Count, Q', 'from django.db.models import Count, Q\nfrom django.db.models.functions import Substr')
        views=replace_once(views,"            qs = qs.filter(path__startswith=folder.rstrip('/')+'/')", """            folder_prefix=folder.rstrip('/')+'/'
            qs = qs.filter(path__startswith=folder_prefix)
            if request.GET.get('folder_scope') == 'direct':
                qs=qs.annotate(_folder_remainder=Substr('path',len(folder_prefix)+1)).exclude(_folder_remainder__contains='/')""")
    changes['vault/views.py']=views
    for name,text in changes.items():
        if (app/name).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='.ui-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','0003_share_link.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'/('ui-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('Ordner und Freigaben in die SkyZ-Oberfläche integriert. Sicherung:',backup)
    print('WebApp vollständig schließen und neu öffnen. Ordner und Freigaben bleiben jetzt in der Hauptansicht.')
    print('Anleitung: /data/skyzfiles/app/OBERFLAECHE.md')

if __name__=='__main__':main()
