// Planu — Deep Android project detection (SPEC-013)
import { join, basename } from 'node:path';
import { safeReadFile, walkForExt } from './mobile-detector-shared.js';
// -- Android constants --------------------------------------------------------
const ANDROID_CAP_KEYS = {
    'com.google.firebase.messaging': 'FCM',
    'com.google.android.gms.wallet': 'Google Pay',
    'com.google.android.gms.maps': 'Google Maps',
    'com.google.android.gms.location': 'Location Services',
    'android.permission.NFC': 'NFC',
};
const GRADLE_SKIP_KEYS = new Set([
    'minSdk',
    'targetSdk',
    'compileSdk',
    'applicationId',
    'namespace',
    'versionCode',
    'versionName',
]);
// -- Android helpers ----------------------------------------------------------
async function readAndroidGradle(projectPath) {
    return ((await safeReadFile(join(projectPath, 'app', 'build.gradle.kts'))) ??
        (await safeReadFile(join(projectPath, 'app', 'build.gradle'))));
}
function extractSdkValue(content, key) {
    const m = new RegExp(`${key}\\s*[=:]\\s*(\\d+)`).exec(content);
    return m?.[1] !== undefined ? parseInt(m[1], 10) : null;
}
export function extractGradleBlock(content, blockName) {
    const m = new RegExp(`${blockName}\\s*\\{([^}]+)\\}`, 's').exec(content);
    if (!m?.[1]) {
        return [];
    }
    const names = [];
    const re = /^\s+([a-z][a-zA-Z0-9_]+)\s*[{(]/gm;
    let nm = re.exec(m[1]);
    while (nm !== null) {
        const name = nm[1];
        /* v8 ignore start */
        if (name && !GRADLE_SKIP_KEYS.has(name)) {
            names.push(name);
        }
        /* v8 ignore stop */
        nm = re.exec(m[1]);
    }
    return names;
}
async function parseSettingsGradle(projectPath) {
    const content = (await safeReadFile(join(projectPath, 'settings.gradle.kts'))) ??
        (await safeReadFile(join(projectPath, 'settings.gradle')));
    if (!content) {
        return [];
    }
    const modules = [];
    const re = /include\s*\(?["']?([^"',)\s]+)["']?\)?/g;
    let m = re.exec(content);
    while (m !== null) {
        const mod = m[1];
        /* v8 ignore start */
        if (mod) {
            modules.push(mod);
        }
        /* v8 ignore stop */
        m = re.exec(content);
    }
    return modules;
}
async function parseAndroidManifest(projectPath) {
    const content = await safeReadFile(join(projectPath, 'app', 'src', 'main', 'AndroidManifest.xml'));
    if (!content) {
        return { permissions: [], capabilities: [] };
    }
    const permissions = [];
    const re = /uses-permission\s+android:name="([^"]+)"/g;
    let m = re.exec(content);
    while (m !== null) {
        const perm = m[1];
        /* v8 ignore start */
        if (perm) {
            permissions.push(perm);
        }
        /* v8 ignore stop */
        m = re.exec(content);
    }
    const caps = new Set();
    for (const [kw, label] of Object.entries(ANDROID_CAP_KEYS)) {
        if (content.includes(kw)) {
            caps.add(label);
        }
    }
    return { permissions, capabilities: [...caps] };
}
// -- Exported detection functions --------------------------------------------
export async function detectDeepAndroid(projectPath) {
    const gradle = await readAndroidGradle(projectPath);
    let minSdk = null;
    let targetSdk = null;
    let compileSdk = null;
    let buildTypes = ['debug', 'release'];
    let productFlavors = [];
    let namespace = null;
    if (gradle) {
        minSdk = extractSdkValue(gradle, 'minSdk');
        targetSdk = extractSdkValue(gradle, 'targetSdk');
        compileSdk = extractSdkValue(gradle, 'compileSdk');
        const custom = extractGradleBlock(gradle, 'buildTypes');
        if (custom.length > 0) {
            buildTypes = [...new Set(['debug', 'release', ...custom])];
        }
        productFlavors = extractGradleBlock(gradle, 'productFlavors');
        namespace =
            /namespace\s*[=\s]*["']([^"']+)["']/m.exec(gradle)?.[1] ??
                /applicationId\s*[=\s]*["']([^"']+)["']/m.exec(gradle)?.[1] ??
                null;
    }
    const buildVariants = productFlavors.length > 0
        ? productFlavors.flatMap((f) => buildTypes.map((b) => `${b}${f.charAt(0).toUpperCase()}${f.slice(1)}`))
        : buildTypes;
    const [modules, { permissions, capabilities }, archPattern] = await Promise.all([
        parseSettingsGradle(projectPath),
        parseAndroidManifest(projectPath),
        detectAndroidArchPattern(projectPath),
    ]);
    return {
        minSdk,
        targetSdk,
        compileSdk,
        buildTypes,
        productFlavors,
        buildVariants,
        namespace,
        modules,
        permissions,
        capabilities,
        archPattern,
    };
}
export async function detectAndroidArchPattern(projectPath) {
    const files = [];
    await walkForExt(projectPath, '.kt', files, 20, 0);
    if (files.length === 0) {
        return null;
    }
    let mviState = false, mviEvent = false, hasVM = false, hasStateFlow = false, hasUseCase = false;
    for (const f of files) {
        const c = await safeReadFile(f);
        if (!c) {
            continue;
        }
        if (/sealed\s+class\s+\w*(State|UiState)/m.test(c)) {
            mviState = true;
        }
        if (/sealed\s+class\s+\w*(Event|Intent|Action)/m.test(c)) {
            mviEvent = true;
        }
        if (c.includes('ViewModel()') || c.includes(': ViewModel()')) {
            hasVM = true;
        }
        if (c.includes('StateFlow') || c.includes('MutableStateFlow')) {
            hasStateFlow = true;
        }
        if (basename(f, '.kt').endsWith('UseCase')) {
            hasUseCase = true;
        }
    }
    if (mviState && mviEvent) {
        return 'mvi';
    }
    if (hasUseCase) {
        return 'clean-architecture';
    }
    if (hasVM && hasStateFlow) {
        return 'mvvm';
    }
    return null;
}
//# sourceMappingURL=mobile-detector-android.js.map