<?php

if (PHP_SAPI !== 'cli') {
    http_response_code(403);
    exit("CLI only\n");
}

$options = getopt('', array(
    'app-root::',
    'env::',
    'scope::',
    'confirm::',
    'json::',
    'help',
));

if (isset($options['help'])) {
    echo "ICYLAB FACTO production read-only probe\n";
    echo "Usage:\n";
    echo "  php scripts/facto_production_probe.php --env=production --scope=metadata --confirm=READ_ONLY_PRODUCTION [--json=/path/report.json]\n\n";
    echo "Scopes:\n";
    echo "  metadata  Authentication plus GET document types, authorizations and branches.\n";
    echo "  full      Also GET one page of documents, inbox and counterparties.\n\n";
    echo "The probe never calls document creation, update, delete, inbox patch or payment endpoints.\n";
    exit(0);
}

$appRoot = isset($options['app-root']) && $options['app-root'] !== false
    ? (string) $options['app-root']
    : dirname(__DIR__);
$appRoot = realpath($appRoot) ?: rtrim($appRoot, DIRECTORY_SEPARATOR);
$environment = strtolower(trim(isset($options['env']) && $options['env'] !== false ? (string) $options['env'] : ''));
$scope = strtolower(trim(isset($options['scope']) && $options['scope'] !== false ? (string) $options['scope'] : 'metadata'));
$confirmation = isset($options['confirm']) && $options['confirm'] !== false ? trim((string) $options['confirm']) : '';
$jsonPath = isset($options['json']) && $options['json'] !== false ? (string) $options['json'] : '';

if ($environment !== 'production') {
    fwrite(STDERR, "ERROR: --env=production is mandatory.\n");
    exit(1);
}
if (!in_array($scope, array('metadata', 'full'), true)) {
    fwrite(STDERR, "ERROR: --scope must be metadata or full.\n");
    exit(1);
}
if (!hash_equals('READ_ONLY_PRODUCTION', $confirmation)) {
    fwrite(STDERR, "ERROR: explicit confirmation is required: --confirm=READ_ONLY_PRODUCTION\n");
    exit(1);
}
if (!is_dir($appRoot)) {
    fwrite(STDERR, "ERROR: application root was not found.\n");
    exit(1);
}

require_once $appRoot . '/core/config.php';
require_once $appRoot . '/core/database.php';
require_once $appRoot . '/services/facto/FactoClient.php';

function probe_explicit_value($name)
{
    if (defined($name)) {
        return trim((string) constant($name));
    }
    $value = getenv($name);
    return $value === false ? '' : trim((string) $value);
}

function probe_count_items($value)
{
    if (!is_array($value)) {
        return 0;
    }
    $isSequential = array_keys($value) === range(0, count($value) - 1);
    if ($isSequential) {
        return count($value);
    }
    foreach (array('data', 'result', 'items', 'rows', 'results', 'documents', 'inbox_documents', 'customers_suppliers') as $key) {
        if (isset($value[$key]) && is_array($value[$key])) {
            $candidate = $value[$key];
            $candidateSequential = array_keys($candidate) === range(0, count($candidate) - 1);
            if ($candidateSequential) {
                return count($candidate);
            }
            foreach (array('data', 'items', 'rows', 'results') as $nested) {
                if (isset($candidate[$nested]) && is_array($candidate[$nested])) {
                    return count($candidate[$nested]);
                }
            }
        }
    }
    return 0;
}

function probe_top_level_keys($value)
{
    if (!is_array($value)) {
        return array();
    }
    $keys = array();
    foreach (array_keys($value) as $key) {
        if (is_string($key)) {
            $lower = strtolower($key);
            if (strpos($lower, 'token') !== false || strpos($lower, 'secret') !== false || strpos($lower, 'password') !== false || strpos($lower, 'authorization') !== false) {
                continue;
            }
            $keys[] = $key;
        }
    }
    return array_slice($keys, 0, 20);
}

function probe_write_json($path, array $report)
{
    if ($path === '') {
        return true;
    }
    $dir = dirname($path);
    if (!is_dir($dir) && !@mkdir($dir, 0750, true)) {
        return false;
    }
    $json = json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    return $json !== false && file_put_contents($path, $json . PHP_EOL, LOCK_EX) !== false;
}

$required = array(
    'ICYLAB_FACTO_PRODUCTION_API_BASE_URL',
    'ICYLAB_FACTO_PRODUCTION_ACCOUNT_ID',
    'ICYLAB_FACTO_PRODUCTION_CLIENT_ID',
    'ICYLAB_FACTO_PRODUCTION_CLIENT_SECRET',
    'ICYLAB_FACTO_PRODUCTION_USERNAME',
    'ICYLAB_FACTO_PRODUCTION_PASSWORD',
);
$missing = array();
$placeholders = array();
foreach ($required as $name) {
    $value = probe_explicit_value($name);
    if ($value === '') {
        $missing[] = $name;
    } elseif (preg_match('/(?:REPLACE_|CHANGEME|YOUR_|EXAMPLE)/i', $value)) {
        $placeholders[] = $name;
    }
}
if (!empty($missing) || !empty($placeholders)) {
    fwrite(STDERR, "ERROR: explicit production FACTO configuration is incomplete or still contains placeholders. Legacy fallback is not accepted.\n");
    if (!empty($missing)) {
        fwrite(STDERR, "Missing names: " . implode(', ', $missing) . "\n");
    }
    if (!empty($placeholders)) {
        fwrite(STDERR, "Placeholder names: " . implode(', ', $placeholders) . "\n");
    }
    exit(1);
}

$baseUrl = probe_explicit_value('ICYLAB_FACTO_PRODUCTION_API_BASE_URL');
$host = parse_url($baseUrl, PHP_URL_HOST);
$host = is_string($host) ? strtolower($host) : '';
if (stripos($baseUrl, 'https://') !== 0 || $host === '' || strpos($host, 'sandbox') !== false || strpos($host, 'test') !== false || strpos($host, 'dev') !== false) {
    fwrite(STDERR, "ERROR: production FACTO URL failed the safety check.\n");
    exit(1);
}

$report = array(
    'tool' => 'ICYLAB FACTO production read-only probe',
    'version' => '5.0.0',
    'generated_at_utc' => gmdate('c'),
    'environment' => 'production',
    'scope' => $scope,
    'host' => $host,
    'operations' => array(),
    'result' => 'FAIL',
);

$operations = array(
    'document_types' => array('required' => true, 'call' => function ($client) { return $client->getDocumentTypes(array('page' => 1, 'per_page' => 100)); }),
    'document_authorizations' => array('required' => true, 'call' => function ($client) { return $client->getDocumentAuthorizations(array('page' => 1, 'per_page' => 100)); }),
    'company_branches' => array('required' => true, 'call' => function ($client) { return $client->getCompanyBranches(array('page' => 1, 'per_page' => 100)); }),
);
if ($scope === 'full') {
    $operations['documents'] = array('required' => true, 'call' => function ($client) { return $client->getDocuments(array('page' => 1, 'per_page' => 1)); });
    $operations['inbox_documents'] = array('required' => true, 'call' => function ($client) { return $client->getInboxDocuments(array('page' => 1, 'per_page' => 1)); });
    $operations['customers_suppliers'] = array('required' => false, 'call' => function ($client) { return $client->getCustomersSuppliers(array('page' => 1, 'per_page' => 1)); });
}

$failedRequired = 0;
$failedOptional = 0;

echo str_repeat('=', 72) . PHP_EOL;
echo "ICYLAB FACTO production read-only probe v5\n";
echo "Host: " . $host . " | Scope: " . $scope . PHP_EOL;
echo "No DTE creation/update/delete or payment endpoint will be called.\n";
echo str_repeat('=', 72) . PHP_EOL;

try {
    $client = new FactoClient('production');
    $settings = $client->getSettingsSummary();
    echo "[INFO] Production client initialized. account_id configured: " . (!empty($settings['account_id_configured']) ? 'yes' : 'no') . PHP_EOL;

    // Authentication is the only POST made by this probe. FactoClient stores the
    // resulting token in the local facto_tokens table; no business document is changed.
    $client->getAccessToken();
    echo "[PASS] Authentication succeeded. Token value was not printed.\n";
    $report['authentication'] = array('status' => 'PASS', 'token_printed' => false, 'local_token_cache_written' => true);

    foreach ($operations as $name => $definition) {
        try {
            $response = $definition['call']($client);
            $entry = array(
                'status' => 'PASS',
                'required' => (bool) $definition['required'],
                'item_count_detected' => probe_count_items($response),
                'top_level_keys' => probe_top_level_keys($response),
            );
            $report['operations'][$name] = $entry;
            echo '[PASS] ' . str_pad($name, 28) . ' GET succeeded; detected items=' . $entry['item_count_detected'] . PHP_EOL;
        } catch (FactoApiException $e) {
            $entry = array(
                'status' => 'FAIL',
                'required' => (bool) $definition['required'],
                'http_code' => $e->getHttpCode(),
                'endpoint' => $e->getEndpoint(),
            );
            $report['operations'][$name] = $entry;
            echo '[FAIL] ' . str_pad($name, 28) . ' GET failed; HTTP=' . $e->getHttpCode() . PHP_EOL;
            if ($definition['required']) {
                $failedRequired++;
            } else {
                $failedOptional++;
            }
        } catch (Throwable $e) {
            $entry = array(
                'status' => 'FAIL',
                'required' => (bool) $definition['required'],
                'error_class' => get_class($e),
            );
            $report['operations'][$name] = $entry;
            echo '[FAIL] ' . str_pad($name, 28) . ' GET failed; review server logs.' . PHP_EOL;
            if ($definition['required']) {
                $failedRequired++;
            } else {
                $failedOptional++;
            }
        }
    }
} catch (FactoApiException $e) {
    echo '[FAIL] Authentication/API initialization failed; HTTP=' . $e->getHttpCode() . PHP_EOL;
    $report['authentication'] = array('status' => 'FAIL', 'http_code' => $e->getHttpCode(), 'endpoint' => $e->getEndpoint());
    $failedRequired++;
} catch (Throwable $e) {
    echo "[FAIL] Authentication/API initialization failed; review configuration and server logs.\n";
    $report['authentication'] = array('status' => 'FAIL', 'error_class' => get_class($e));
    $failedRequired++;
}

$report['summary'] = array('required_failures' => $failedRequired, 'optional_failures' => $failedOptional);
$report['result'] = $failedRequired > 0 ? 'FAIL' : ($failedOptional > 0 ? 'WARN' : 'PASS');

echo str_repeat('=', 72) . PHP_EOL;
echo 'Result: ' . $report['result'] . ' | required failures=' . $failedRequired . ' | optional failures=' . $failedOptional . PHP_EOL;

if ($jsonPath !== '') {
    if (probe_write_json($jsonPath, $report)) {
        echo 'JSON report: ' . $jsonPath . PHP_EOL;
    } else {
        echo "[FAIL] JSON report could not be written.\n";
        $report['result'] = 'FAIL';
        $failedRequired++;
    }
}

exit($failedRequired > 0 ? 1 : ($failedOptional > 0 ? 2 : 0));
