<?php
require_once __DIR__ . '/../core/config.php';
require_once __DIR__ . '/../services/billing/BillingRuntimeGate.php';

function method_body($path, $method)
{
    $src = file_get_contents($path);
    if ($src === false) return null;
    $pattern = '/function\\s+' . preg_quote($method, '/') . '\\s*\\([^)]*\\)\\s*\\{/m';
    if (!preg_match($pattern, $src, $m, PREG_OFFSET_CAPTURE)) return null;
    $start = $m[0][1] + strlen($m[0][0]);
    $depth = 1;
    $len = strlen($src);
    for ($i = $start; $i < $len; $i++) {
        if ($src[$i] === '{') $depth++;
        elseif ($src[$i] === '}') {
            $depth--;
            if ($depth === 0) return substr($src, $start, $i - $start);
        }
    }
    return null;
}

$root = dirname(__DIR__);
$checks = array(
    array('services/billing/BillingReceivablesService.php', 'listReceivables', array('refreshCalculatedReceivableStatuses(', 'ensureCollectionsForEnvironment(', 'resolveCustomers(')),
    array('services/billing/BillingReceivablesService.php', 'getDocument', array('ensureDocumentCustomerAndCollection(', 'refreshCalculatedReceivableStatuses(')),
    array('services/billing/BillingPayablesService.php', 'listPayables', array('resolveSupplierDefaults(', 'refreshCalculatedPayableStatuses(', 'refreshOverdue(')),
    array('services/billing/BillingPayablesService.php', 'getKpis', array('resolveSupplierDefaults(', 'refreshCalculatedPayableStatuses(', 'refreshOverdue(')),
    array('services/billing/BillingPayablesService.php', 'getDocument', array('resolveDocumentByLocalId(', 'refreshCalculatedPayableStatuses(')),
    array('services/billing/BillingSupplierAgingService.php', 'summary', array('refreshBaseState(')),
    array('services/billing/BillingSupplierAgingService.php', 'detail', array('refreshBaseState(')),
);

$failures = 0;
echo "ICYLAB BILLING FINANCE READ ISOLATION DIAGNOSTIC v6.12\n";
echo "Generated at UTC: " . gmdate('Y-m-d H:i:s') . "\n";
echo "App root: {$root}\n";
echo "DB name: " . (defined('ICYLAB_DB_NAME') ? ICYLAB_DB_NAME : '(undefined)') . "\n";
echo "Default FACTO environment: " . (defined('ICYLAB_FACTO_ENVIRONMENT') ? ICYLAB_FACTO_ENVIRONMENT : '(undefined)') . "\n\n";

foreach ($checks as $check) {
    list($rel, $method, $banned) = $check;
    $body = method_body($root . '/' . $rel, $method);
    if ($body === null) {
        echo "{$rel}::{$method}: FAIL method not found\n";
        $failures++;
        continue;
    }
    $found = array();
    foreach ($banned as $token) {
        if (strpos($body, $token) !== false) $found[] = $token;
    }
    if ($found) {
        echo "{$rel}::{$method}: FAIL banned=" . implode(',', $found) . "\n";
        $failures++;
    } else {
        echo "{$rel}::{$method}: PASS side-effect-free\n";
    }
}

$payables = file_get_contents($root . '/services/billing/BillingPayablesService.php');
if ($payables !== false && strpos($payables, 'effectivePayableStatusSql') !== false && strpos($payables, 'deriveEffectivePayableStatus') !== false) {
    echo "payables_effective_status_projection: PASS\n";
} else {
    echo "payables_effective_status_projection: FAIL\n";
    $failures++;
}

echo "\nRUNTIME GATES\n";
foreach (array('read','finance','issue') as $op) {
    echo "production/{$op}: " . (billing_runtime_gate_allows($op, 'production') ? 'ALLOWED' : 'BLOCKED') . "\n";
}

echo "\nRESULT: " . ($failures === 0 ? 'PASS' : 'FAIL') . "\n";
exit($failures === 0 ? 0 : 1);
