<?php

declare(strict_types=1);

function dental_audit_chain_heads_table(): string
{
    return table('audit_chain_heads');
}

function dental_audit_integrity_snapshots_table(): string
{
    return table('audit_integrity_snapshots');
}

function dental_audit_chain_schema_ready(): bool
{
    $auditTable = table('audit_logs');
    return schema_table_exists($auditTable)
        && schema_column_exists($auditTable, 'chain_key')
        && schema_column_exists($auditTable, 'chain_sequence')
        && schema_column_exists($auditTable, 'previous_hash')
        && schema_column_exists($auditTable, 'integrity_version')
        && schema_table_exists(dental_audit_chain_heads_table());
}

function dental_audit_chain_zero_hash(): string
{
    return str_repeat('0', 64);
}

function dental_audit_chain_key(?int $branchId): string
{
    return $branchId !== null && $branchId > 0 ? 'branch:' . $branchId : 'global';
}

function dental_audit_chain_lock(PDO $pdo, string $chainKey): array
{
    $heads = dental_audit_chain_heads_table();
    $insert = $pdo->prepare(
        'INSERT IGNORE INTO `' . $heads . '` '
        . '(chain_key,last_sequence,last_audit_id,last_hash,created_at,updated_at) '
        . 'VALUES (?,0,NULL,?,NOW(),NOW())'
    );
    $insert->execute([$chainKey, dental_audit_chain_zero_hash()]);

    $stmt = $pdo->prepare('SELECT chain_key,last_sequence,last_audit_id,last_hash FROM `' . $heads . '` WHERE chain_key=? FOR UPDATE');
    $stmt->execute([$chainKey]);
    $row = $stmt->fetch();
    if (!$row) throw new RuntimeException('The audit-chain head could not be locked.');
    return $row;
}

function dental_audit_chain_update_head(PDO $pdo, string $chainKey, int $sequence, int $auditId, string $hash): void
{
    $stmt = $pdo->prepare(
        'UPDATE `' . dental_audit_chain_heads_table() . '` '
        . 'SET last_sequence=?,last_audit_id=?,last_hash=?,updated_at=NOW() '
        . 'WHERE chain_key=?'
    );
    $stmt->execute([$sequence, $auditId, $hash, $chainKey]);
    if ($stmt->rowCount() !== 1) throw new RuntimeException('The audit-chain head could not be updated.');
}

function dental_audit_integrity_snapshot_create(int $limit = 5000): array
{
    if (!schema_table_exists(dental_audit_integrity_snapshots_table())) {
        throw new RuntimeException('The audit-integrity snapshot table is unavailable.');
    }
    $summary = audit_integrity_summary($limit);
    $status = ($summary['ready'] ?? false)
        && (int)($summary['invalid'] ?? 0) === 0
        && (int)($summary['broken_links'] ?? 0) === 0
        && (int)($summary['head_mismatches'] ?? 0) === 0
        ? 'verified' : 'failed';
    $tipHash = trim((string)($summary['latest_chain_hash'] ?? ''));
    $stmt = db()->prepare(
        'INSERT INTO `' . dental_audit_integrity_snapshots_table() . '` '
        . '(status,checked_rows,valid_rows,invalid_rows,unhashed_rows,broken_links,head_mismatches,latest_audit_id,tip_hash,summary_json,verified_by,verified_at) '
        . 'VALUES (?,?,?,?,?,?,?,?,?,?,?,NOW())'
    );
    $stmt->execute([
        $status,
        (int)($summary['checked'] ?? 0),
        (int)($summary['valid'] ?? 0),
        (int)($summary['invalid'] ?? 0),
        (int)($summary['unhashed'] ?? 0),
        (int)($summary['broken_links'] ?? 0),
        (int)($summary['head_mismatches'] ?? 0),
        (int)($summary['latest_id'] ?? 0),
        $tipHash !== '' ? $tipHash : null,
        json_encode($summary, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        current_user()['id'] ?? null,
    ]);
    $id = (int)db()->lastInsertId();
    audit_required('audit_integrity_verified', 'audit_integrity_snapshot', $id, [
        'status' => $status,
        'checked_rows' => (int)($summary['checked'] ?? 0),
        'invalid_rows' => (int)($summary['invalid'] ?? 0),
        'broken_links' => (int)($summary['broken_links'] ?? 0),
        'head_mismatches' => (int)($summary['head_mismatches'] ?? 0),
        'tip_hash' => $tipHash,
    ]);
    return ['id' => $id, 'status' => $status, 'summary' => $summary];
}

function dental_audit_integrity_latest_snapshot(): ?array
{
    if (!schema_table_exists(dental_audit_integrity_snapshots_table())) return null;
    $row = db()->query('SELECT * FROM `' . dental_audit_integrity_snapshots_table() . '` ORDER BY id DESC LIMIT 1')->fetch();
    return $row ?: null;
}
