<?php
require_once __DIR__ . '/../core/config.php';

$root = dirname(__DIR__);
$checks = array();

function v618_check(&$checks, $label, $ok)
{
    $checks[] = array($label, (bool)$ok);
    echo $label . ': ' . ($ok ? 'PASS' : 'FAIL') . PHP_EOL;
}

function v618_source($root, $path)
{
    $value = @file_get_contents($root . '/' . $path);
    return $value === false ? '' : $value;
}

$q = v618_source($root, 'modules/crm/quote_save_ajax.php');
$quotes = v618_source($root, 'modules/crm/quotes.php');
$sync = v618_source($root, 'services/facto/FactoDocumentsSyncService.php');
$reception = v618_source($root, 'services/billing/BillingInboxReceptionService.php');
$cxc = v618_source($root, 'services/billing/BillingReceivablesService.php');
$cxp = v618_source($root, 'services/billing/BillingPayablesService.php');
$issue = v618_source($root, 'services/billing/BillingIssueService.php');
$docsPage = v618_source($root, 'modules/billing/documents.php');
$docsJs = v618_source($root, 'modules/billing/documents.js');
$cxcPage = v618_source($root, 'modules/billing/receivables.php');
$cxcJs = v618_source($root, 'modules/billing/receivables.js');
$cxpPage = v618_source($root, 'modules/billing/payables.php');
$receivePage = v618_source($root, 'modules/billing/receive.php');
$css = v618_source($root, 'assets/css/10-billing.css');

v618_check(
    $checks,
    'Quote path contains no typed properties incompatible with the web handler',
    strpos(v618_source($root, 'services/crm/QuoteLifecycleService.php'), 'private PDO $pdo') === false
    && strpos(v618_source($root, 'services/crm/TimelineAuditService.php'), 'private PDO $pdo') === false
    && strpos(v618_source($root, 'services/billing/BillingUnifiedIssuerService.php'), 'private PDO $pdo') === false
);

v618_check(
    $checks,
    'Quote endpoint catches service load failures and always emits safe JSON',
    strpos($q, 'function q_save_json_response') !== false
    && strpos($q, 'JSON_INVALID_UTF8_SUBSTITUTE') !== false
    && strpos($q, "try {\n    require_once '../../services/crm/QuoteNumberService.php';") !== false
    && strpos($q, 'catch (Throwable $e)') !== false
);

v618_check(
    $checks,
    'Quote UI detects empty and non-JSON responses',
    strpos($quotes, 'respuesta vacía') !== false
    && strpos($quotes, 'respuesta no válida') !== false
    && strpos($quotes, 'return r.text()') !== false
);

v618_check(
    $checks,
    'Issued invoices create CxC during issue and during productive sync catch-up',
    strpos($issue, "'receivable'") !== false
    && strpos($sync, 'materializeIssuedInvoiceReceivable') !== false
    && strpos($sync, "array(2, 32, 46)") !== false
    && strpos($sync, "billing_runtime_gate_allows('finance'") !== false
);

v618_check(
    $checks,
    'Approved received invoices create CxP only for invoice types 9 and 33',
    strpos($reception, 'shouldCreatePayableFromApprovedInvoice') !== false
    && strpos($reception, "array('approved', 'approved_with_observations')") !== false
    && strpos($reception, 'array(9, 33)') !== false
    && strpos($reception, 'Cuenta por pagar creada automáticamente al aprobar la recepción de la factura.') !== false
);

v618_check(
    $checks,
    'CxC lists all document families while writes remain invoice-only',
    strpos($cxc, 'document_family') !== false
    && strpos($cxc, 'is_financial_document') !== false
    && strpos($cxc, 'array(2, 32, 46)') !== false
);

v618_check(
    $checks,
    'CxP lists all document families while writes remain invoice-only',
    strpos($cxp, 'document_family') !== false
    && strpos($cxp, 'isPayableDocumentType') !== false
    && strpos($cxp, 'array(9, 33)') !== false
);

v618_check(
    $checks,
    'Grouped table containers and vertical scroll are installed',
    strpos($docsPage, 'documentsGroups') !== false
    && strpos($cxcPage, 'receivablesGroups') !== false
    && strpos($cxpPage, 'payablesGroups') !== false
    && strpos($css, '.billing-document-group-scroll') !== false
    && strpos($css, 'overflow:auto') !== false
);

v618_check(
    $checks,
    'Operational environment selectors and sandbox list disclaimer are removed',
    strpos($docsPage, '<select id="documentsEnv"') === false
    && strpos($cxcPage, '<select id="receivablesEnv"') === false
    && strpos($cxpPage, '<select id="payablesEnv"') === false
    && strpos($receivePage, '<select id="receiveEnv"') === false
    && strpos($docsPage, '<strong>Sandbox:</strong>') === false
);

v618_check(
    $checks,
    'Frontend state does not call the DOM helper before it is declared',
    strpos($docsJs, "env: 'production'") !== false
    && strpos($cxcJs, "const state = { env: 'production'") !== false
    && strpos($cxpPage, "const state = { env: 'production'") !== false
);

v618_check(
    $checks,
    'Grouped selection controls contain no stale global checkbox IDs',
    strpos($cxcJs, 'receivablesSelectAll') === false
    && strpos($cxpPage, 'payablesSelectAll') === false
    && strpos($cxcJs, 'receivables-select-all-group') !== false
    && strpos($cxpPage, 'payables-select-all-group') !== false
);

v618_check(
    $checks,
    'List limits cover the current productive inbox inventory',
    strpos($cxcJs, "p.set('limit', '1000')") !== false
    && strpos($cxpPage, "limit:'1000'") !== false
);

v618_check(
    $checks,
    'Production issue remains blocked by configuration',
    defined('ICYLAB_BILLING_PRODUCTION_ISSUE_ENABLED')
        ? ICYLAB_BILLING_PRODUCTION_ISSUE_ENABLED === false
        : true
);

$failed = array_filter($checks, function ($row) {
    return !$row[1];
});

echo PHP_EOL . 'RESULT: ' . (count($failed) === 0 ? 'PASS' : 'FAIL') . PHP_EOL;
exit(count($failed) === 0 ? 0 : 1);
