/* eslint-disable @typescript-eslint/no-var-requires */
/**
 * Expo Config-Plugin — bindet das NEURLFilter-ExtensionKit-Target
 * (`RebreakURLFilterExtension`) beim Prebuild ins iOS-Projekt ein.
 *
 * Ersetzt das frühere NEFilter-Plugin. Erkenntnis aus Apples `SimpleURLFilter`-
 * Sample: das Target ist KEIN exotischer Produkttyp — es bleibt das klassische
 * `app_extension`. Die ExtensionKit-Natur kommt aus:
 *   1. der Info.plist (`EXAppExtensionAttributes` / `EXExtensionPointIdentifier`)
 *   2. der Embed-Phase „Embed Foundation Extensions" mit `dstSubfolderSpec = 16`
 *      (das klassische „Embed App Extensions" wäre 13).
 *
 * Was es macht:
 *   1) Haupt-App-Entitlements (url-filter-provider, family-controls, app-groups)
 *   2) kopiert `modules/rebreak-protection/ios/RebreakURLFilterExtension/` → `ios/`
 *   3) fügt das Xcode-Target `RebreakURLFilterExtension` hinzu
 *
 * Idempotent — kann beliebig oft via `expo prebuild` laufen.
 */

const fs = require('fs');
const path = require('path');

const {
  withEntitlementsPlist,
  withDangerousMod,
  withXcodeProject,
} = require('@expo/config-plugins');

const APP_GROUP = 'group.org.rebreak.app';
const TARGET_NAME = 'RebreakURLFilterExtension';
const EXT_BUNDLE_SUFFIX = 'URLFilterExtension'; // → org.rebreak.app.URLFilterExtension
const DEVELOPMENT_TEAM = '84BQ7MTFYK';
const MODULE_DIR = path.join(
  __dirname,
  '..',
  'modules',
  'rebreak-protection',
  'ios',
  TARGET_NAME,
);

// Swift-Quellen (Apple-Bloom vendored + unser Control-Provider).
const SWIFT_SOURCES = [
  'BloomFilter.swift',
  'Murmur3Hash.swift',
  'FNV1aHash.swift',
  'RebreakURLFilterControlProvider.swift',
];
// Bundle-Resources.
const RESOURCES = ['bloom_filter.plist'];

// ─── Packet-Tunnel-Extension (Layer 1 — Default-Filter) ──────────────────────
// Neues Target: der NEPacketTunnelProvider-DNS-Sinkhole. Ersetzt NEURLFilter
// als primären, lieferbaren iOS-Filter. KLASSISCHE PluginKit-App-Extension —
// normaler `app_extension`-Pfad, normale „Embed App Extensions"-Phase
// (dstSubfolderSpec 13). KEIN ExtensionKit-Sonderweg.
const PT_TARGET_NAME = 'RebreakPacketTunnelExtension';
const PT_BUNDLE_SUFFIX = 'PacketTunnelExtension'; // → org.rebreak.app.PacketTunnelExtension
const PT_MODULE_DIR = path.join(
  __dirname,
  '..',
  'modules',
  'rebreak-protection',
  'ios',
  PT_TARGET_NAME,
);
// Swift-Quellen (Provider + Filter-Logik, aus Android nach Swift portiert).
const PT_SWIFT_SOURCES = [
  'PacketTunnelProvider.swift',
  'DnsFilter.swift',
  'HashList.swift',
  'DomainHasher.swift',
];

// ─── Content-Filter-Extension (Layer 1 — Supervised-Pfad) ────────────────────
// Klassischer NEFilterDataProvider — wiederbelebt aus a80cc8b. Wird auf
// supervised-MDM-Geräten als Layer 1 statt PacketTunnel aktiviert (kein VPN-
// Toggle für den User). Dynamische Hash-Liste aus App-Group blocklist.bin.
// KEIN PIR-Server, KEIN ExtensionKit-Sonderweg — klassische dst-13-PlugIns/.
const CF_TARGET_NAME = 'RebreakContentFilter';
const CF_BUNDLE_SUFFIX = 'ContentFilterExtension'; // → org.rebreak.app.ContentFilterExtension
const CF_MODULE_DIR = path.join(
  __dirname,
  '..',
  'modules',
  'rebreak-protection',
  'ios',
  CF_TARGET_NAME,
);
const CF_SWIFT_SOURCES = ['FilterDataProvider.swift'];

// ─── 1) Haupt-App-Entitlements ──────────────────────────────────────────────

function withMainAppEntitlements(config) {
  return withEntitlementsPlist(config, (cfg) => {
    // NetworkExtension-Entitlement.
    //  - packet-tunnel-provider: PacketTunnel-DNS-Sinkhole (unsupervised-Pfad,
    //    User-toggleable VPN)
    //  - content-filter-provider: klassisches NEFilter (supervised-Pfad, kein
    //    User-Toggle in Settings)
    // App entscheidet zur Laufzeit per isMdmSupervised welcher Stack aktiviert
    // wird — beide Entitlements müssen verfügbar sein.
    cfg.modResults['com.apple.developer.networking.networkextension'] = [
      'packet-tunnel-provider',
      'content-filter-provider',
    ];
    // Family Controls = Kern-Funktion, Apple-Distribution-Entitlement freigegeben
    // (v0.3.4) → DEFAULT AN. Nur ein explizites REBREAK_ENABLE_FAMILY_CONTROLS=0
    // schaltet es ab (Escape-Hatch). Muss identisch zu app.config.ts
    // `familyControlsEnabled` bleiben.
    if (process.env.REBREAK_ENABLE_FAMILY_CONTROLS !== '0') {
      cfg.modResults['com.apple.developer.family-controls'] = true;
    }
    const groups = cfg.modResults['com.apple.security.application-groups'] || [];
    if (!groups.includes(APP_GROUP)) {
      cfg.modResults['com.apple.security.application-groups'] = [...groups, APP_GROUP];
    }
    return cfg;
  });
}

// ─── 2) Extension-Sources ins ios/-Verzeichnis kopieren ─────────────────────

function withCopyExtensionSources(config) {
  return withDangerousMod(config, [
    'ios',
    async (cfg) => {
      // Extension-Verzeichnis(se) nach ios/ kopieren.
      for (const [target, srcDir] of [
        [PT_TARGET_NAME, PT_MODULE_DIR],
        [CF_TARGET_NAME, CF_MODULE_DIR],
      ]) {
        const dest = path.join(cfg.modRequest.platformProjectRoot, target);
        if (!fs.existsSync(srcDir)) {
          throw new Error(
            `[with-rebreak-protection-ios] Extension source dir missing: ${srcDir}`,
          );
        }
        if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
        for (const file of fs.readdirSync(srcDir)) {
          fs.copyFileSync(path.join(srcDir, file), path.join(dest, file));
        }
      }
      return cfg;
    },
  ]);
}

// ─── 3) Xcode-Target hinzufügen ──────────────────────────────────────────────

function withExtensionTarget(config) {
  return withXcodeProject(config, async (cfg) => {
    const proj = cfg.modResults;

    // Idempotenz: skip wenn Target schon angelegt.
    if (proj.pbxTargetByName(TARGET_NAME)) {
      return cfg;
    }

    const mainBundleId = cfg.ios?.bundleIdentifier;
    if (!mainBundleId) {
      throw new Error('[with-rebreak-protection-ios] ios.bundleIdentifier fehlt in app.config');
    }
    const extBundleId = `${mainBundleId}.${EXT_BUNDLE_SUFFIX}`;

    // ── Target anlegen (Produkttyp app_extension — wie Apples SimpleURLFilter) ──
    const target = proj.addTarget(TARGET_NAME, 'app_extension', TARGET_NAME, extBundleId);

    // ── Build-Phasen ──
    proj.addBuildPhase(SWIFT_SOURCES, 'PBXSourcesBuildPhase', 'Sources', target.uuid);
    proj.addBuildPhase(RESOURCES, 'PBXResourcesBuildPhase', 'Resources', target.uuid);
    proj.addBuildPhase(
      ['NetworkExtension.framework'],
      'PBXFrameworksBuildPhase',
      'Frameworks',
      target.uuid,
    );

    // ── PBXGroup für die Extension-Dateien ──
    const pbxGroup = proj.addPbxGroup(
      [...SWIFT_SOURCES, ...RESOURCES, 'Info.plist', `${TARGET_NAME}.entitlements`],
      TARGET_NAME,
      TARGET_NAME,
    );
    const groups = proj.hash.project.objects.PBXGroup;
    Object.keys(groups).forEach((key) => {
      if (
        groups[key].name === 'CustomTemplate' ||
        (groups[key].name === undefined && groups[key].path === undefined)
      ) {
        proj.addToPbxGroup(pbxGroup.uuid, key);
      }
    });

    // ── Build-Settings auf der Target-Configuration ──
    const configurations = proj.pbxXCBuildConfigurationSection();
    Object.keys(configurations)
      .filter((k) => typeof configurations[k] === 'object')
      .forEach((k) => {
        const buildSettingsObj = configurations[k].buildSettings;
        if (
          buildSettingsObj &&
          buildSettingsObj.PRODUCT_NAME &&
          buildSettingsObj.PRODUCT_NAME.replace(/"/g, '') === TARGET_NAME
        ) {
          buildSettingsObj.INFOPLIST_FILE = `"${TARGET_NAME}/Info.plist"`;
          buildSettingsObj.CODE_SIGN_ENTITLEMENTS = `"${TARGET_NAME}/${TARGET_NAME}.entitlements"`;
          // NEURLFilter ist iOS 26+. Die Extension lädt nur dort — höheres
          // Deployment-Target als die Haupt-App (iOS 16+) ist korrekt.
          buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET = '26.0';
          buildSettingsObj.SWIFT_VERSION = '5.0';
          buildSettingsObj.TARGETED_DEVICE_FAMILY = '"1,2"';
          buildSettingsObj.CODE_SIGN_STYLE = 'Automatic';
          // EAS managed credentials setzen DEVELOPMENT_TEAM nur auf der Main-App
          // → Extension braucht expliziten Team-Wert.
          buildSettingsObj.DEVELOPMENT_TEAM = DEVELOPMENT_TEAM;
        }
      });

    // ── Embed-Phase auf ExtensionKit umstellen ──
    // proj.addTarget() hat bereits eine „Copy Files"-PBXCopyFilesBuildPhase
    // (dstSubfolderSpec 13 = PlugIns/) im Haupt-Target angelegt, die unsere
    // .appex einbettet. iOS' Installer (MIPluginKitBundle) behandelt aber
    // ALLES in PlugIns/ als klassische PluginKit-Extension und verlangt ein
    // NSExtension-Dict im Info.plist — das ExtensionKit-Extensions NICHT haben
    // ("AppexBundleMissingNSExtensionDict", MIInstallerError 39). ExtensionKit-
    // Extensions MÜSSEN nach Extensions/. Also die bestehende Phase umbiegen:
    // dstSubfolderSpec 16 + dstPath $(EXTENSIONS_FOLDER_PATH) — exakt wie
    // Apples SimpleURLFilter.xcodeproj. KEINE zweite Phase anlegen (sonst wird
    // die .appex doppelt eingebettet).
    const mainTargetUuid = proj.getFirstTarget().uuid;
    const copyFilesPhases = proj.hash.project.objects.PBXCopyFilesBuildPhase || {};
    let embedFixed = false;
    Object.keys(copyFilesPhases).forEach((key) => {
      const phase = copyFilesPhases[key];
      if (typeof phase !== 'object') return;
      const embedsOurAppex = (phase.files || []).some(
        (f) => typeof f?.comment === 'string' && f.comment.includes(`${TARGET_NAME}.appex`),
      );
      if (!embedsOurAppex) return;
      phase.name = '"Embed Foundation Extensions"';
      phase.dstSubfolderSpec = 16;
      phase.dstPath = '"$(EXTENSIONS_FOLDER_PATH)"';
      embedFixed = true;
    });
    if (!embedFixed) {
      throw new Error(
        '[with-rebreak-protection-ios] Embed-CopyFiles-Phase für die .appex nicht gefunden',
      );
    }

    // ── Target-Dependency: Haupt-App baut die Extension vorher ──
    proj.addTargetDependency(mainTargetUuid, [target.uuid]);

    return cfg;
  });
}

// ─── 4) Packet-Tunnel-Xcode-Target hinzufügen ────────────────────────────────
//
// KLASSISCHE App-Extension — anders als das NEURLFilter-Target:
//  - normaler `app_extension`-Produkttyp,
//  - „Embed App Extensions"-Phase mit dstSubfolderSpec 13 (PlugIns/),
//  - KEIN ExtensionKit-Sonderweg (kein dstSubfolderSpec 16, kein
//    EXAppExtensionAttributes).
//  - Deployment-Target = Main-App (iOS 16), KEIN 26.0-Gate.
//
// ACHTUNG: `addTarget` legt zwar eine korrekte dst-13-Phase an, embedded die
// .appex aber wegen einer Eigenheit der `xcode`-Lib in die NEURLFilter-dst-16-
// Phase (siehe ausführliche Begründung am Embed-Phase-Fix unten). Darum MUSS
// die .appex hier explizit in die eigene dst-13-Phase umgehängt werden.

function withPacketTunnelTarget(config) {
  return withXcodeProject(config, async (cfg) => {
    const proj = cfg.modResults;

    // Idempotenz: skip wenn Target schon angelegt.
    if (proj.pbxTargetByName(PT_TARGET_NAME)) {
      return cfg;
    }

    const mainBundleId = cfg.ios?.bundleIdentifier;
    if (!mainBundleId) {
      throw new Error('[with-rebreak-protection-ios] ios.bundleIdentifier fehlt in app.config');
    }
    const extBundleId = `${mainBundleId}.${PT_BUNDLE_SUFFIX}`;

    // ── Target anlegen (klassischer app_extension-Produkttyp) ──
    const target = proj.addTarget(
      PT_TARGET_NAME,
      'app_extension',
      PT_TARGET_NAME,
      extBundleId,
    );

    // ── Build-Phasen ──
    proj.addBuildPhase(
      PT_SWIFT_SOURCES,
      'PBXSourcesBuildPhase',
      'Sources',
      target.uuid,
    );
    proj.addBuildPhase(
      ['NetworkExtension.framework'],
      'PBXFrameworksBuildPhase',
      'Frameworks',
      target.uuid,
    );

    // ── PBXGroup für die Extension-Dateien ──
    const pbxGroup = proj.addPbxGroup(
      [...PT_SWIFT_SOURCES, 'Info.plist', `${PT_TARGET_NAME}.entitlements`],
      PT_TARGET_NAME,
      PT_TARGET_NAME,
    );
    const groups = proj.hash.project.objects.PBXGroup;
    Object.keys(groups).forEach((key) => {
      if (
        groups[key].name === 'CustomTemplate' ||
        (groups[key].name === undefined && groups[key].path === undefined)
      ) {
        proj.addToPbxGroup(pbxGroup.uuid, key);
      }
    });

    // ── Build-Settings auf der Target-Configuration ──
    const configurations = proj.pbxXCBuildConfigurationSection();
    Object.keys(configurations)
      .filter((k) => typeof configurations[k] === 'object')
      .forEach((k) => {
        const buildSettingsObj = configurations[k].buildSettings;
        if (
          buildSettingsObj &&
          buildSettingsObj.PRODUCT_NAME &&
          buildSettingsObj.PRODUCT_NAME.replace(/"/g, '') === PT_TARGET_NAME
        ) {
          buildSettingsObj.INFOPLIST_FILE = `"${PT_TARGET_NAME}/Info.plist"`;
          buildSettingsObj.CODE_SIGN_ENTITLEMENTS = `"${PT_TARGET_NAME}/${PT_TARGET_NAME}.entitlements"`;
          // Packet-Tunnel läuft ab iOS 16 — Deployment-Target = Main-App.
          buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET = '16.0';
          buildSettingsObj.SWIFT_VERSION = '5.0';
          buildSettingsObj.TARGETED_DEVICE_FAMILY = '"1,2"';
          buildSettingsObj.CODE_SIGN_STYLE = 'Automatic';
          // EAS managed credentials setzen DEVELOPMENT_TEAM nur auf der Main-App
          // → Extension braucht expliziten Team-Wert.
          buildSettingsObj.DEVELOPMENT_TEAM = DEVELOPMENT_TEAM;
        }
      });

    // ── Embed-Phase korrigieren — die .appex MUSS allein in dst 13 (PlugIns/) ──
    //
    // BUG (verifiziert gegen node_modules/xcode/lib/pbxProject.js + einen
    // End-to-End-Lauf der echten Plugin-Kette):
    //
    //  1. `withXcodeProject`-Mods laufen LIFO — `withPacketTunnelTarget` ist
    //     zuletzt registriert und läuft daher ZUERST, `withExtensionTarget`
    //     (NEURLFilter) DANACH.
    //  2. `proj.addTarget('app_extension')` ruft intern (via `addProductFile`)
    //     `addToPbxCopyfilesBuildPhase`, BEVOR die neue dst-13-Copy-Files-Phase
    //     existiert. `buildPhaseObject` findet im neuen Target keine eigene
    //     Phase und fällt auf die ERSTE PBXCopyFilesBuildPhase zurück, deren
    //     SECTION-COMMENT exakt „Copy Files" ist — projektweit.
    //  3. Ergebnis ohne Fix: die NEURLFilter-`addTarget` (läuft als zweites)
    //     biegt seine Phase per `phase.name`/`dstSubfolderSpec` auf dst 16 um,
    //     lässt den SECTION-COMMENT aber auf „Copy Files". Beim PacketTunnel-
    //     `addTarget` matcht `buildPhaseObject` diesen Comment und pusht die
    //     PacketTunnel-.appex in dieselbe dst-16-Phase. → .appex landet in
    //     `ReBreak.app/Extensions/` statt `PlugIns/` → Install-Crash
    //     `AppexBundleMissingEXAppExtensionAttributesDict` (klassische
    //     NSExtension im ExtensionKit-Ordner).
    //
    // Fix (zwei Teile, beide nötig):
    //  (a) Die PacketTunnel-.appex aus JEDER Copy-Files-Phase herausziehen und
    //      exklusiv in die eigene, von `addTarget` angelegte dst-13-Phase legen.
    //  (b) Den SECTION-COMMENT dieser dst-13-Phase von „Copy Files" auf
    //      „Embed App Extensions" umbenennen. SONST matcht der NACH uns laufende
    //      `withExtensionTarget`-`addTarget`-Aufruf via `buildPhaseObject(
    //      'Copy Files')` unsere PacketTunnel-Phase und der dortige dst-16-Umbau
    //      zieht die PacketTunnel-.appex erneut mit. Comment-Rename entkoppelt
    //      beide Phasen sauber (NEURLFilters eigener Umbau matcht per
    //      .appex-Dateiname, nicht per Comment — bleibt also korrekt).
    const ptCopyFilesPhases = proj.hash.project.objects.PBXCopyFilesBuildPhase || {};
    const ptPhaseKeys = Object.keys(ptCopyFilesPhases).filter(
      (k) => typeof ptCopyFilesPhases[k] === 'object' && !/_comment$/.test(k),
    );

    // (a) Den PacketTunnel-.appex-BuildFile-Eintrag finden und aus ALLEN
    //     Copy-Files-Phasen entfernen.
    let ptAppexBuildFile = null;
    ptPhaseKeys.forEach((key) => {
      const phase = ptCopyFilesPhases[key];
      const kept = [];
      (phase.files || []).forEach((f) => {
        if (
          typeof f?.comment === 'string' &&
          f.comment.includes(`${PT_TARGET_NAME}.appex`)
        ) {
          ptAppexBuildFile = f;
        } else {
          kept.push(f);
        }
      });
      phase.files = kept;
    });
    if (!ptAppexBuildFile) {
      throw new Error(
        '[with-rebreak-protection-ios] PacketTunnel-.appex-BuildFile nicht gefunden',
      );
    }

    // (b) Die von addTarget frisch angelegte (jetzt leere) dst-13-Phase finden,
    //     die .appex exklusiv dort einhängen UND den Section-Comment umbenennen.
    //     dst 13 = PlugIns/ = der korrekte Ort für eine klassische NSExtension-
    //     PluginKit-Extension.
    const ptDst13Key = ptPhaseKeys.find(
      (k) =>
        ptCopyFilesPhases[k].dstSubfolderSpec === 13 &&
        (ptCopyFilesPhases[k].files || []).length === 0,
    );
    if (!ptDst13Key) {
      throw new Error(
        '[with-rebreak-protection-ios] keine leere dst-13-Copy-Files-Phase für die PacketTunnel-.appex gefunden',
      );
    }
    ptCopyFilesPhases[ptDst13Key].name = '"Embed App Extensions"';
    ptCopyFilesPhases[ptDst13Key].files = [ptAppexBuildFile];
    // Section-Comment-Key umbenennen — entkoppelt die Phase vom
    // `buildPhaseObject('Copy Files')`-Lookup des NEURLFilter-Targets.
    const ptDst13CommentKey = `${ptDst13Key}_comment`;
    if (ptCopyFilesPhases[ptDst13CommentKey] === 'Copy Files') {
      ptCopyFilesPhases[ptDst13CommentKey] = 'Embed App Extensions';
    }
    // Auch den Build-Phase-Verweis im Target auf den neuen Comment ziehen,
    // damit pbxproj-Serialisierung + Xcode-Anzeige konsistent bleiben.
    const ptNativeTargets = proj.hash.project.objects.PBXNativeTarget || {};
    Object.keys(ptNativeTargets).forEach((tk) => {
      const nt = ptNativeTargets[tk];
      if (typeof nt !== 'object' || !Array.isArray(nt.buildPhases)) return;
      nt.buildPhases.forEach((bp) => {
        if (bp.value === ptDst13Key && bp.comment === 'Copy Files') {
          bp.comment = 'Embed App Extensions';
        }
      });
    });

    // ── Target-Dependency: Haupt-App baut die Extension vorher ──
    const mainTargetUuid = proj.getFirstTarget().uuid;
    proj.addTargetDependency(mainTargetUuid, [target.uuid]);

    return cfg;
  });
}

// ─── 5) Content-Filter-Xcode-Target hinzufügen ───────────────────────────────
//
// 1:1 zum PacketTunnel-Hook: klassische app_extension, dst-13 PlugIns/,
// derselbe Embed-Phase-Fix (Comment-Rename, exklusive .appex-Zuweisung).
// LIFO-Composition: dieser Hook läuft NACH PacketTunnel — wenn PT seine Phase
// bereits umbenannt hat ("Embed App Extensions"), findet `addProductFile` keine
// "Copy Files"-Phase mehr und legt eine frische dst-13 für CF an, die wir hier
// dann gleich richtig setzen.

function withContentFilterTarget(config) {
  return withXcodeProject(config, async (cfg) => {
    const proj = cfg.modResults;

    if (proj.pbxTargetByName(CF_TARGET_NAME)) {
      return cfg;
    }

    const mainBundleId = cfg.ios?.bundleIdentifier;
    if (!mainBundleId) {
      throw new Error('[with-rebreak-protection-ios] ios.bundleIdentifier fehlt in app.config');
    }
    const extBundleId = `${mainBundleId}.${CF_BUNDLE_SUFFIX}`;

    const target = proj.addTarget(
      CF_TARGET_NAME,
      'app_extension',
      CF_TARGET_NAME,
      extBundleId,
    );

    proj.addBuildPhase(
      CF_SWIFT_SOURCES,
      'PBXSourcesBuildPhase',
      'Sources',
      target.uuid,
    );
    proj.addBuildPhase(
      ['NetworkExtension.framework'],
      'PBXFrameworksBuildPhase',
      'Frameworks',
      target.uuid,
    );

    const pbxGroup = proj.addPbxGroup(
      [...CF_SWIFT_SOURCES, 'Info.plist', `${CF_TARGET_NAME}.entitlements`],
      CF_TARGET_NAME,
      CF_TARGET_NAME,
    );
    const groups = proj.hash.project.objects.PBXGroup;
    Object.keys(groups).forEach((key) => {
      if (
        groups[key].name === 'CustomTemplate' ||
        (groups[key].name === undefined && groups[key].path === undefined)
      ) {
        proj.addToPbxGroup(pbxGroup.uuid, key);
      }
    });

    const configurations = proj.pbxXCBuildConfigurationSection();
    Object.keys(configurations)
      .filter((k) => typeof configurations[k] === 'object')
      .forEach((k) => {
        const buildSettingsObj = configurations[k].buildSettings;
        if (
          buildSettingsObj &&
          buildSettingsObj.PRODUCT_NAME &&
          buildSettingsObj.PRODUCT_NAME.replace(/"/g, '') === CF_TARGET_NAME
        ) {
          buildSettingsObj.INFOPLIST_FILE = `"${CF_TARGET_NAME}/Info.plist"`;
          buildSettingsObj.CODE_SIGN_ENTITLEMENTS = `"${CF_TARGET_NAME}/${CF_TARGET_NAME}.entitlements"`;
          // NEFilterDataProvider gibt es seit iOS 9 — Deployment-Target = Main-App.
          buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET = '16.0';
          buildSettingsObj.SWIFT_VERSION = '5.0';
          buildSettingsObj.TARGETED_DEVICE_FAMILY = '"1,2"';
          buildSettingsObj.CODE_SIGN_STYLE = 'Automatic';
          buildSettingsObj.DEVELOPMENT_TEAM = DEVELOPMENT_TEAM;
        }
      });

    // Embed-Phase-Fix (siehe ausführliche Begründung im PacketTunnel-Hook).
    // .appex aus allen Copy-Files-Phasen ziehen und exklusiv in eigene dst-13
    // legen + Section-Comment auf "Embed App Extensions" umbenennen.
    const cfCopyFilesPhases = proj.hash.project.objects.PBXCopyFilesBuildPhase || {};
    const cfPhaseKeys = Object.keys(cfCopyFilesPhases).filter(
      (k) => typeof cfCopyFilesPhases[k] === 'object' && !/_comment$/.test(k),
    );

    let cfAppexBuildFile = null;
    cfPhaseKeys.forEach((key) => {
      const phase = cfCopyFilesPhases[key];
      const kept = [];
      (phase.files || []).forEach((f) => {
        if (
          typeof f?.comment === 'string' &&
          f.comment.includes(`${CF_TARGET_NAME}.appex`)
        ) {
          cfAppexBuildFile = f;
        } else {
          kept.push(f);
        }
      });
      phase.files = kept;
    });
    if (!cfAppexBuildFile) {
      throw new Error(
        '[with-rebreak-protection-ios] ContentFilter-.appex-BuildFile nicht gefunden',
      );
    }

    const cfDst13Key = cfPhaseKeys.find(
      (k) =>
        cfCopyFilesPhases[k].dstSubfolderSpec === 13 &&
        (cfCopyFilesPhases[k].files || []).length === 0,
    );
    if (!cfDst13Key) {
      throw new Error(
        '[with-rebreak-protection-ios] keine leere dst-13-Copy-Files-Phase für die ContentFilter-.appex gefunden',
      );
    }
    cfCopyFilesPhases[cfDst13Key].name = '"Embed App Extensions"';
    cfCopyFilesPhases[cfDst13Key].files = [cfAppexBuildFile];
    const cfDst13CommentKey = `${cfDst13Key}_comment`;
    if (cfCopyFilesPhases[cfDst13CommentKey] === 'Copy Files') {
      cfCopyFilesPhases[cfDst13CommentKey] = 'Embed App Extensions';
    }
    const cfNativeTargets = proj.hash.project.objects.PBXNativeTarget || {};
    Object.keys(cfNativeTargets).forEach((tk) => {
      const nt = cfNativeTargets[tk];
      if (typeof nt !== 'object' || !Array.isArray(nt.buildPhases)) return;
      nt.buildPhases.forEach((bp) => {
        if (bp.value === cfDst13Key && bp.comment === 'Copy Files') {
          bp.comment = 'Embed App Extensions';
        }
      });
    });

    const mainTargetUuid = proj.getFirstTarget().uuid;
    proj.addTargetDependency(mainTargetUuid, [target.uuid]);

    return cfg;
  });
}

// ─── Composition ────────────────────────────────────────────────────────────

module.exports = function withRebreakProtectionIos(config) {
  config = withMainAppEntitlements(config);
  config = withCopyExtensionSources(config);
  // withExtensionTarget (NEURLFilter, iOS 26 + PIR) entfernt — `url-filter-provider`
  // ist kein gültiger EAS-Entitlement-Wert.
  // ContentFilter (klassisches NEFilter) zuerst registrieren — läuft per LIFO
  // NACH PacketTunnel, was dem Embed-Phase-Fix in beiden Hooks sauber entkoppelt.
  config = withContentFilterTarget(config);
  config = withPacketTunnelTarget(config);
  return config;
};
