#!/usr/bin/env python3
from pathlib import Path
import re, sys, xml.etree.ElementTree as ET
root=Path(__file__).resolve().parents[1]
errors=[]
def need(c,m):
    if not c: errors.append(m)
def text(rel):
    p=root/rel
    if not p.exists(): errors.append(f'missing {rel}'); return ''
    return p.read_text(errors='ignore')

# XML validity
xml_files=list(root.rglob('*.xml'))
for p in xml_files:
    try: ET.parse(p)
    except Exception as e: errors.append(f'XML parse failed {p.relative_to(root)}: {e}')

manifest=text('AndroidManifest.xml'); bp=text('Android.bp')
need('package="com.lemenzo.files"' in manifest,'package must be com.lemenzo.files')
need('name: "LemenzoFiles"' in bp,'LemenzoFiles app module missing')
need('name: "privapp_whitelist_com.lemenzo.files"' in bp,'self-contained privapp whitelist module missing')
need('required: ["privapp_whitelist_com.lemenzo.files"]' in bp,'LemenzoFiles must require its privapp whitelist')
need('name: "DocumentsUI"' not in bp,'stale DocumentsUI app module remains')

# No stale source/package/build identity
for p in root.rglob('*'):
    if not p.is_file() or p.name in {'lint-baseline.xml','lemenzo_validate_static.py','validate_static.py','LEMENZO_FILES.md','LEMENZO_RELEASE.md'}: continue
    try: s=p.read_text(errors='ignore')
    except Exception: continue
    need('com.android.documentsui' not in s,f'stale com.android.documentsui in {p.relative_to(root)}')
    need('com/android/documentsui' not in s,f'stale com/android/documentsui path in {p.relative_to(root)}')
need(not (root/'res/flag(com.android.documentsui.flags.use_material3)').exists(),'stale DocumentsUI flag resource directory')
need((root/'res/flag(com.lemenzo.files.flags.use_material3)').exists(),'Lemenzo M3 flag resource directory missing')

# SAF / system file-picker contracts
for action in ['android.intent.action.OPEN_DOCUMENT','android.intent.action.CREATE_DOCUMENT','android.intent.action.GET_CONTENT','android.intent.action.OPEN_DOCUMENT_TREE']:
    need(action in manifest,f'missing SAF action {action}')
need('android.permission.MANAGE_DOCUMENTS' in manifest,'MANAGE_DOCUMENTS missing')
for auth in ['com.lemenzo.files.lastAccessed','com.lemenzo.files.pickCountRecord','com.lemenzo.files.archives']:
    need(auth in manifest,f'missing provider authority {auth}')

# Privacy
need('android.permission.INTERNET' not in manifest,'production INTERNET permission present')
need('android:allowBackup="false"' in manifest,'backup must remain disabled')
need('com.google.android.backup.api_key' not in manifest,'Google backup key present')
for p in (root/'src').rglob('*'):
    if p.is_file() and p.suffix in {'.java','.kt'}:
        s=p.read_text(errors='ignore').lower()
        need('play.google.com/store' not in s,f'Google Play fallback in {p.relative_to(root)}')

# Privapp XML
perm=root/'privapp-permissions-com.lemenzo.files.xml'
need(perm.exists(),'privapp permissions XML missing')
if perm.exists():
    r=ET.parse(perm).getroot(); need(r.tag=='permissions','privapp XML root must be <permissions>')
    node=r.find('privapp-permissions'); need(node is not None,'privapp-permissions node missing')
    if node is not None: need(node.attrib.get('package')=='com.lemenzo.files','privapp package mismatch')

# Locale config + official exact parity
need('android:localeConfig="@xml/locale_config"' in manifest,'localeConfig missing')
lc=root/'res/xml/locale_config.xml'
if lc.exists():
    ns='{http://schemas.android.com/apk/res/android}name'
    langs=[e.attrib.get(ns) for e in ET.parse(lc).getroot()]
    need(langs==['en','da','sv','de','es'],f'locale_config mismatch: {langs}')
else: errors.append('locale_config.xml missing')
folders=['values','values-da','values-sv','values-de','values-es']; sets={}
for f in folders:
    p=root/'res'/f/'strings.xml'
    if not p.exists(): errors.append(f'missing {p.relative_to(root)}'); continue
    elems=ET.parse(p).getroot().findall('string'); names=[e.attrib.get('name') for e in elems if e.attrib.get('name')]
    need(len(names)==len(set(names)),f'{f} duplicate string keys'); sets[f]=set(names)
if 'values' in sets:
    for f in folders[1:]:
        if f in sets: need(sets[f]==sets['values'],f'{f} string parity mismatch')
for p in root.glob('res/values*/strings.xml'):
    try: rr=ET.parse(p).getroot()
    except: continue
    labels=[e.text for e in rr.findall('string') if e.attrib.get('name')=='files_label']
    need(not labels or labels[0]=='Lemenzo Files',f'{p.relative_to(root)} files_label mismatch')

# Launcher and feature wiring
need('#000000' in text('res/values/ic_launcher_background.xml'),'launcher background must be black')
need((root/'res/drawable-nodpi/lemenzo_files_logo.png').exists(),'Lemenzo Files logo missing')
need('new Intent(this, HomeActivity.class)' in text('src/com/lemenzo/files/files/LauncherActivity.java'),'launcher must open Lemenzo Home')
classes=['HomeActivity','AboutActivity','FavoritesActivity','ToolsActivity','StorageAnalyzerActivity','DuplicateFinderActivity','IntegrityActivity','PrivateShareActivity','MetadataInspectorActivity','ApkInspectorActivity','DuplicateReviewActivity','EcosystemActivity','SmartSearchActivity','CleanupAdvisorActivity','PdfInspectorActivity']
for cls in classes:
    need((root/f'src/com/lemenzo/files/lemenzo/{cls}.java').exists(),f'{cls} missing')
    need(f'android:name=".lemenzo.{cls}"' in manifest,f'{cls} manifest entry missing')
need('DocumentsContract.deleteDocument' in text('src/com/lemenzo/files/lemenzo/DuplicateReviewActivity.java'),'safe duplicate delete missing')
need('SHA-512' in text('src/com/lemenzo/files/lemenzo/IntegrityActivity.java'),'SHA-512 missing')
need('com.lemenzo.gallery' in text('src/com/lemenzo/files/lemenzo/EcosystemActivity.java'),'Gallery integration missing')
need('com.lemenzo.camera' in text('src/com/lemenzo/files/lemenzo/EcosystemActivity.java'),'Camera integration missing')
for rel in ['res/menu/activity.xml','res/flag(com.lemenzo.files.flags.use_material3)/menu/activity_m3.xml']:
    t=text(rel); need('option_menu_lemenzo_tools' in t,f'{rel}: Tools missing'); need('option_menu_lemenzo_about' in t,f'{rel}: About missing')


# Regression: when file picking, directory MIME must be appended without overwriting the caller MIME.
action=(root/"src/com/lemenzo/files/AbstractActionHandler.java").read_text()
if "acceptMimes[mimeCount - 1]" in action:
    errors.append("Picker MIME regression: directory MIME overwrites the final caller MIME")
if "acceptMimes[mimeCount] = DocumentsContract.Document.MIME_TYPE_DIR" not in action:
    errors.append("Picker MIME regression guard missing: directory MIME must be appended")

if errors:
    print('STATIC VALIDATION: FAIL')
    for e in errors: print(' -',e)
    sys.exit(1)
print('STATIC VALIDATION: PASS')
print(f'XML: PASS ({len(xml_files)})')
print('STANDALONE IDENTITY: PASS')
print('SAF SYSTEM ROLE: PASS')
print('PRIVACY BASELINE: PASS')
print('PRIVAPP ALLOWLIST: PASS')
print('OFFICIAL LOCALE PARITY: PASS')
print('LEMENZO FEATURE WIRING: PASS')
