from pathlib import Path
import xml.etree.ElementTree as ET, re, sys
root=Path(__file__).resolve().parents[1];errors=[]
for p in root.rglob("*.xml"):
    try: ET.parse(p)
    except Exception as e: errors.append(f"XML {p.relative_to(root)}: {e}")
for p in (root/"src").rglob("*.java"):
    t=p.read_text()
    if t.count("{")!=t.count("}"): errors.append(f"Brace imbalance: {p.relative_to(root)}")
manifest=(root/"AndroidManifest.xml").read_text()
for perm in ["READ_CONTACTS","WRITE_CONTACTS"]:
    if perm not in manifest: errors.append("Missing permission "+perm)
if "INTERNET" in manifest: errors.append("INTERNET permission must not be present")
base={e.attrib["name"] for e in ET.parse(root/"res/values/strings.xml").getroot().findall("string")}
for p in (root/"res").glob("values-*/strings.xml"):
    cur={e.attrib["name"] for e in ET.parse(p).getroot().findall("string")}
    if cur!=base: errors.append(f"Locale mismatch {p.parent.name}: missing={sorted(base-cur)} extra={sorted(cur-base)}")
repo=(root/"src/com/lemenzo/contacts/ContactsRepository.java").read_text()
if "deleteLocal" not in repo: errors.append("Missing safe local RawContact delete")
if "getForEdit" not in repo: errors.append("Missing local-only editor read")
if 'MIMETYPE+" IN (' not in repo: errors.append("Missing MIME-scoped edit")
detail=(root/"src/com/lemenzo/contacts/ContactDetailActivity.java").read_text()
if "repo.delete(id)" in detail: errors.append("Unsafe aggregate contact delete")

codec=(root/"src/com/lemenzo/contacts/ContactFileCodec.java").read_text()
for token in ["detectDelimiter", "QUOTED-PRINTABLE", "splitStructured", "formattedAddress", "hasImportableData"]:
    if token not in codec: errors.append("Missing robust contact import codec feature: "+token)
imp=(root/"src/com/lemenzo/contacts/ImportExportActivity.java").read_text()
for token in ["text/x-vcard", "application/vcard", "Intent.EXTRA_MIME_TYPES", "isExpectedFile"]:
    if token not in imp: errors.append("Missing VCF/CSV picker compatibility: "+token)


# Runtime permission entry points must protect provider writes/reads even when MainActivity is bypassed.
editor=(root/"src/com/lemenzo/contacts/ContactEditorActivity.java").read_text()
proxy=(root/"src/com/lemenzo/contacts/SystemContactIntentActivity.java").read_text()
helper=(root/"src/com/lemenzo/contacts/ContactsPermission.java").read_text()
for token in ["ContactsPermission.hasReadWrite", "REQ_CONTACTS", "onRequestPermissionsResult", "contact_save_failed"]:
    if token not in editor: errors.append("Editor permission/save hardening missing: "+token)
for token in ["ContactsPermission.hasReadWrite", "REQ_CONTACTS", "onRequestPermissionsResult"]:
    if token not in proxy: errors.append("System contact intent permission hardening missing: "+token)
for token in ["READ_CONTACTS", "WRITE_CONTACTS", "requestReadWrite"]:
    if token not in helper: errors.append("Permission helper missing: "+token)
strings=ET.parse(root/"res/values/strings.xml").getroot()
sm={e.attrib["name"]:(e.text or "").strip() for e in strings.findall("string")}
if sm.get("app_name")!="Contacts": errors.append("Launcher app_name must be Contacts")
if sm.get("app_title")!="Lemenzo Contacts": errors.append("Internal app_title must be Lemenzo Contacts")

print("XML/JAVA/PRIVACY/LOCALE/DATA-INTEGRITY/PERMISSIONS/BRANDING:", "PASS" if not errors else "FAIL")
for e in errors: print(e)
sys.exit(1 if errors else 0)
