#!/usr/bin/env python3
import os, json, subprocess, sys, re, shutil, time
from pathlib import Path

ACCOUNT='friday.uplink@gmail.com'
ROOT_ID='174EDgu3zltV9VtpHYH6AWcZiR_hYDVnp'
# Prioritize project folders first; ERNE_Wissen can be very large (SIA PDFs).
TARGETS={
    'Projekte': '1-ulLnXpK0tLVRbW7kJFr6On-jRw9AGUK',
    'ERNE_Wissen': '1LuFcKR2UbGu0rSp3SiD_j9wfgbjEEWt4',
}
BASE=Path('/home/agent/jarvis_memory/work')
RAW_BASE=BASE/'_drive_sources'/'ERNE'
PROJECT_BASE=BASE/'projects'
WISSEN_BASE=BASE/'erne_wissen'
MIME_FOLDER='application/vnd.google-apps.folder'
GOOGLE_PREFIX='application/vnd.google-apps.'

def run(cmd, timeout=120):
    env=os.environ.copy()
    env.setdefault('HOME','/home/agent')
    env.setdefault('XDG_CONFIG_HOME','/home/agent/.config')
    # source secrets in shell so password not printed
    full="set -a; source /home/agent/.hermes/secrets/gog_keyring.env; set +a; " + cmd
    p=subprocess.run(['bash','-lc',full], text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout)
    if p.returncode!=0:
        raise RuntimeError(f'CMD failed {p.returncode}: {cmd}\nSTDOUT:{p.stdout[-1000:]}\nSTDERR:{p.stderr[-1000:]}')
    return p.stdout

def ls_parent(folder_id):
    q=f"'{folder_id}' in parents and trashed = false"
    out=run(f"gog -a {ACCOUNT} drive search {shlex_quote(q)} --max 1000 --json --results-only --no-input", timeout=120)
    data=json.loads(out or '[]')
    if isinstance(data, dict) and 'files' in data: data=data['files']
    return sorted(data, key=lambda x:(x.get('mimeType')!=MIME_FOLDER, x.get('name','').lower()))

def shlex_quote(s):
    import shlex
    return shlex.quote(s)

def safe_name(name):
    name=name.replace('/','_').replace('\x00','')
    return re.sub(r'[\r\n\t]+',' ',name).strip() or 'unnamed'

def slugify(name):
    s=name.lower()
    trans=str.maketrans({'ö':'oe','ä':'ae','ü':'ue','é':'e','è':'e','à':'a','ç':'c','ß':'ss'})
    s=s.translate(trans)
    s=re.sub(r'[^a-z0-9]+','_',s).strip('_')
    return s or 'project'

def ext_for_google(mime, name):
    if mime.endswith('.document'): return '.docx'
    if mime.endswith('.spreadsheet'): return '.xlsx'
    if mime.endswith('.presentation'): return '.pptx'
    if mime.endswith('.drawing'): return '.pdf'
    return ''

manifest=[]
errors=[]

def crawl(folder_id, rel_parts):
    items=ls_parent(folder_id)
    for it in items:
        name=safe_name(it.get('name','unnamed'))
        mime=it.get('mimeType','')
        fid=it.get('id')
        rel=rel_parts+[name]
        if mime==MIME_FOLDER:
            crawl(fid, rel)
        else:
            local_dir=RAW_BASE.joinpath(*rel_parts)
            local_dir.mkdir(parents=True, exist_ok=True)
            out_name=name
            if mime.startswith(GOOGLE_PREFIX) and not Path(out_name).suffix:
                out_name += ext_for_google(mime,name)
            out_path=local_dir/out_name
            # For knowledge retrieval, office/PDF/text files matter most. Large recordings
            # are kept as Drive links in the manifest unless already downloaded from an earlier run.
            skip_binary_media = mime.startswith('video/') or mime.startswith('audio/')
            if out_path.exists() and out_path.stat().st_size>0:
                status='exists'
            elif skip_binary_media:
                status='linked_only_media_not_downloaded'
            else:
                fmt=''
                if mime.startswith(GOOGLE_PREFIX):
                    if mime.endswith('.document'): fmt=' --format docx'
                    elif mime.endswith('.spreadsheet'): fmt=' --format xlsx'
                    elif mime.endswith('.presentation'): fmt=' --format pptx'
                    else: fmt=' --format pdf'
                try:
                    run(f"gog -a {ACCOUNT} drive download {shlex_quote(fid)} --out {shlex_quote(str(out_path))}{fmt} --json --no-input", timeout=300)
                    status='downloaded'
                except Exception as e:
                    errors.append({'path':'/'.join(rel), 'id':fid, 'mimeType':mime, 'error':str(e)[:1500]})
                    status='error'
            manifest.append({
                'drive_path':'/'.join(rel), 'name':name, 'id':fid, 'mimeType':mime,
                'modifiedTime': it.get('modifiedTime'), 'webViewLink': it.get('webViewLink'),
                'local_path': str(out_path), 'status': status,
                'size': out_path.stat().st_size if out_path.exists() else 0
            })

for name, fid in TARGETS.items():
    crawl(fid,[name])

RAW_BASE.mkdir(parents=True, exist_ok=True)
(RAW_BASE/'manifest.json').write_text(json.dumps(manifest, indent=2, ensure_ascii=False), encoding='utf-8')
(RAW_BASE/'errors.json').write_text(json.dumps(errors, indent=2, ensure_ascii=False), encoding='utf-8')
print(json.dumps({'downloaded_or_existing':len([m for m in manifest if m['status']!='error']), 'errors':len(errors), 'raw_base':str(RAW_BASE)}, ensure_ascii=False))
