<?php

declare(strict_types=1);

namespace App\Services\Audit;

use InvalidArgumentException;

/**
 * Shared config hash-chain for 6 audit tables.
 *
 * Single source of truth for writer (db/schema.sql trigger audit_chain_hash()),
 * verify (App\Console\Commands\VerifyAuditChains) and rebuild
 * (App\Console\Commands\AuditRebuildChain).
 *
 * ADR-018: per-tenant via RLS scope for tenant tables,
 * global for BYPASSRLS tables.
 *
 * columns: list in ordinal_position order from db/schema.sql.
 *   '__log_hash__' -- marker for log_hash position -> NULL::bytea in ROW().
 *
 * partition: SQL fragment for OVER (PARTITION BY ... ORDER BY id),
 *   reproducing the RLS-scope of the trigger.
 *   '' = global chain within partition (for BYPASSRLS tables).
 */
final class AuditChainConfig
{
    /**
     * @var array<string, array{columns: list<string>, partition: string}>
     */
    public const TABLES = [
        'auth_log' => [
            'columns' => [
                'id', 'actor_type', 'tenant_id', 'user_id', 'saas_admin_user_id',
                'email', 'event', 'ip_address', 'user_agent', 'failure_reason',
                '__log_hash__', 'created_at',
            ],
            'partition' => '',
        ],
        'activity_log' => [
            'columns' => [
                'id', 'tenant_id', 'user_id', 'deal_id', 'event',
                'old_value', 'new_value', 'context', 'ip_address', 'user_agent',
                '__log_hash__', 'created_at',
            ],
            'partition' => 'PARTITION BY tenant_id',
        ],
        'tenant_operations_log' => [
            'columns' => [
                'id', 'tenant_id', 'user_id', 'entity_type', 'entity_id',
                'event', 'payload_before', 'payload_after', 'ip_address', 'user_agent',
                '__log_hash__', 'created_at',
            ],
            'partition' => 'PARTITION BY tenant_id',
        ],
        'balance_transactions' => [
            'columns' => [
                'id', 'tenant_id', 'type', 'amount_rub', 'amount_leads',
                'balance_rub_after', 'balance_leads_after', 'description',
                'related_type', 'related_id', 'user_id', 'admin_user_id',
                '__log_hash__', 'created_at',
            ],
            'partition' => 'PARTITION BY tenant_id',
        ],
        'pd_processing_log' => [
            'columns' => [
                'id', 'tenant_id', 'subject_type', 'subject_id', 'action',
                'purpose', 'actor_tenant_user_id', 'actor_admin_user_id', 'ip_address',
                '__log_hash__', 'created_at',
            ],
            'partition' => 'PARTITION BY tenant_id',
        ],
        'saas_admin_audit_log' => [
            'columns' => [
                'id', 'admin_user_id', 'action', 'target_type', 'target_id',
                'target_tenant_id', 'payload_before', 'payload_after', 'reason',
                'ip_address', 'user_agent', 'requires_approval', 'approved_by', 'approved_at',
                '__log_hash__', 'created_at',
            ],
            'partition' => '',
        ],
    ];

    /**
     * Build ROW(col1, col2, ..., NULL::bytea, ..., coln) with NULL::bytea at log_hash position.
     *
     * @throws InvalidArgumentException if table is not registered in TABLES
     */
    public static function rowExpression(string $table): string
    {
        if (! isset(self::TABLES[$table])) {
            throw new InvalidArgumentException(
                "Table '{$table}' is not registered in AuditChainConfig::TABLES"
            );
        }

        $parts = [];
        foreach (self::TABLES[$table]['columns'] as $col) {
            $parts[] = ($col === '__log_hash__') ? 'NULL::bytea' : "t.{$col}";
        }

        return 'ROW('.implode(', ', $parts).')';
    }
}
