<?php

declare(strict_types=1);

/**
 * DentalCare release hardening helpers.
 * These checks protect generated installer/update packages from carrying live runtime data.
 */

function dental_release_table_exists(PDO $pdo, string $tableName): bool
{
    try {
        $stmt = $pdo->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=? AND table_name=?');
        $stmt->execute([(string) app_config('database.name'), $tableName]);
        return (int) $stmt->fetchColumn() > 0;
    } catch (Throwable) {
        return false;
    }
}

function dental_release_file_summary(string $path): array
{
    return [
        'path' => $path,
        'exists' => is_file(DENTAL_ROOT . '/' . ltrim($path, '/')),
    ];
}

function dental_release_package_service_loaded(): bool
{
    if (class_exists('InstallerPackageService')) {
        return true;
    }
    $servicePath = DENTAL_ROOT . '/app/Services/InstallerPackageService.php';
    if (!is_file($servicePath)) {
        return false;
    }
    require_once $servicePath;
    return class_exists('InstallerPackageService');
}

function dental_release_package_policy_checks(): array
{
    if (dental_release_package_service_loaded() && method_exists('InstallerPackageService', 'releaseSafetyChecklist')) {
        $rows = InstallerPackageService::releaseSafetyChecklist();
        return array_map(static function (array $row): array {
            $row['status'] = !empty($row['ready']) ? 'Protected' : 'Needs review';
            if (!isset($row['failures']) || !is_array($row['failures'])) {
                $row['failures'] = [];
            }
            return $row;
        }, $rows);
    }

    return [[
        'label' => 'Installer package service available',
        'ready' => false,
        'status' => 'Needs review',
        'failures' => ['app/Services/InstallerPackageService.php'],
    ]];
}

function dental_release_package_policy_ready(): bool
{
    if (dental_release_package_service_loaded() && method_exists('InstallerPackageService', 'releaseSafetyReady')) {
        return InstallerPackageService::releaseSafetyReady();
    }
    foreach (dental_release_package_policy_checks() as $check) {
        if (empty($check['ready'])) return false;
    }
    return true;
}

function dental_release_policy_failure_labels(): array
{
    $labels = [];
    foreach (dental_release_package_policy_checks() as $check) {
        if (!empty($check['ready'])) continue;
        $label = (string)($check['label'] ?? 'Unnamed policy');
        $failures = array_filter(array_map('strval', (array)($check['failures'] ?? [])));
        $labels[] = $failures ? $label . ': ' . implode(', ', array_slice($failures, 0, 4)) : $label;
    }
    return $labels;
}

function dental_release_runtime_warning_checks(): array
{
    $paths = [
        'error_log' => 'Root PHP error log should not be distributed.',
        'api/error_log' => 'API PHP error log should not be distributed.',
        'storage/runtime/sessions' => 'Live sessions must stay out of release/update ZIPs.',
        'storage/private' => 'Private patient files must stay out of release/update ZIPs.',
        'storage/generated-installers' => 'Previously generated packages must stay out of new packages.',
        'storage/backups' => 'Backups must not be bundled into installer/update packages.',
        'config/generated.php' => 'Live database/SMTP configuration must never be in a release package.',
    ];
    $rows = [];
    foreach ($paths as $path => $note) {
        $absolute = DENTAL_ROOT . '/' . $path;
        $exists = is_file($absolute) || is_dir($absolute);
        $rows[] = [
            'path' => $path,
            'exists' => $exists,
            'status' => $exists ? 'Live-only / excluded from package' : 'Not present',
            'note' => $note,
        ];
    }
    return $rows;
}

function dental_release_backup_readiness(PDO $pdo): array
{
    $ready = false;
    $latest = null;
    $count = 0;
    if (dental_release_table_exists($pdo, table('backup_logs'))) {
        try {
            $stmt = $pdo->query('SELECT id,file_name,backup_type,file_size,checksum_sha256,verified_at,created_at FROM `' . table('backup_logs') . '` ORDER BY created_at DESC,id DESC LIMIT 1');
            $latest = $stmt ? $stmt->fetch(PDO::FETCH_ASSOC) : null;
            $count = (int) $pdo->query('SELECT COUNT(*) FROM `' . table('backup_logs') . '`')->fetchColumn();
            $ready = (bool) $latest && !empty($latest['checksum_sha256']) && !empty($latest['verified_at']);
        } catch (Throwable) {
            $latest = null;
        }
    }
    return [
        'ready' => $ready,
        'count' => $count,
        'latest' => $latest ?: null,
        'status' => $ready ? 'Verified backup available' : 'Create and verify a backup before client release',
    ];
}

function dental_release_storage_readiness(): array
{
    $paths = [
        'storage' => DENTAL_ROOT . '/storage',
        'storage/backups' => DENTAL_ROOT . '/storage/backups',
        'storage/generated-installers' => DENTAL_ROOT . '/storage/generated-installers',
    ];
    $rows = [];
    foreach ($paths as $label => $path) {
        $exists = is_dir($path);
        $writable = $exists && is_writable($path);
        $rows[] = [
            'label' => $label,
            'exists' => $exists,
            'writable' => $writable,
            'status' => $writable ? 'Writable' : ($exists ? 'Not writable' : 'Not created yet'),
        ];
    }
    return $rows;
}

function dental_release_hardening_summary(PDO $pdo): array
{
    $policy = dental_release_package_policy_checks();
    $policyReady = dental_release_package_policy_ready();
    $backup = dental_release_backup_readiness($pdo);
    $storage = dental_release_storage_readiness();
    $auditTableReady = dental_release_table_exists($pdo, table('release_hardening_audits'));

    return [
        'ready' => $auditTableReady && $policyReady && is_file(DENTAL_ROOT . '/app/Services/InstallerPackageService.php'),
        'audit_table_ready' => $auditTableReady,
        'package_policy_ready' => $policyReady,
        'package_policy' => $policy,
        'runtime_warnings' => dental_release_runtime_warning_checks(),
        'backup' => $backup,
        'storage' => $storage,
    ];
}

function dental_release_hardening_ready(PDO $pdo): bool
{
    $summary = dental_release_hardening_summary($pdo);
    return !empty($summary['ready']);
}

function dental_release_hardening_record(PDO $pdo, string $status = 'passed'): void
{
    if (!dental_release_table_exists($pdo, table('release_hardening_audits'))) return;
    $summary = dental_release_hardening_summary($pdo);
    $policyFailures = [];
    foreach ($summary['package_policy'] as $row) {
        if (empty($row['ready'])) $policyFailures[] = $row['label'];
    }
    $stmt = $pdo->prepare(
        'INSERT INTO `' . table('release_hardening_audits') . '` '
        . '(audit_status, package_policy_status, backup_status, failed_items_json, summary_json, reviewed_by, reviewed_at, created_at) '
        . 'VALUES (?,?,?,?,?,?,NOW(),NOW())'
    );
    $stmt->execute([
        $status,
        $summary['package_policy_ready'] ? 'passed' : 'needs_review',
        $summary['backup']['ready'] ? 'verified_backup_available' : 'backup_recommended',
        json_encode($policyFailures, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
        json_encode($summary, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
        (int) (current_user()['id'] ?? 0),
    ]);
}
