<?php

declare(strict_types=1);

namespace App\Support\AuditLogDisplay;

use App\Filament\Resources\DberpAuditLogs\DberpAuditLogResource;
use App\Models\DberpAuditLog;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

/**
 * 审计列表按请求批次分组时的组键、标题与条数展示。
 */
final class DberpAuditLogBatchGroupPresenter
{
    private const NO_BATCH_PREFIX = 'no-batch:';

    /**
     * @var array<string, int>
     */
    private array $counts = [];

    public function groupKey(DberpAuditLog $record): string
    {
        $correlationId = $record->correlation_id;

        if ($correlationId !== null && $correlationId !== '') {
            return $correlationId;
        }

        return self::NO_BATCH_PREFIX.$record->getKey();
    }

    public function title(DberpAuditLog $record): string
    {
        $timestamp = DberpAuditLogResource::formatAuditLogTimestamp($record->created_at);
        $operator = filled($record->user?->name)
            ? (string) $record->user->name
            : (string) __('dberp.audit.operator_system');
        $count = $this->countFor($record);
        $summary = app(DberpAuditLogDisplayFormatter::class)->buildView($record)->operationSummary;

        $parts = array_filter([
            $timestamp,
            $operator,
            $this->batchLabel($record),
            trans_choice('dberp.audit.batch_record_count', $count, ['count' => $count]),
            $summary,
        ], static fn (?string $part): bool => $part !== null && $part !== '');

        return implode(' · ', $parts);
    }

    public function description(DberpAuditLog $record): ?string
    {
        if ($record->correlation_id === null || $record->correlation_id === '') {
            return (string) __('dberp.audit.batch_no_correlation_hint');
        }

        return (string) __('dberp.audit.batch_correlation_hint', [
            'id' => $record->correlation_id,
        ]);
    }

    /**
     * @param  Collection<int, DberpAuditLog>  $logs
     */
    public function preloadCountsForLogs(Collection $logs, ?Builder $filteredQuery): void
    {
        $this->counts = [];

        $correlationIds = $logs
            ->pluck('correlation_id')
            ->filter(static fn (?string $id): bool => filled($id))
            ->unique()
            ->values();

        $countsByCorrelation = [];

        if ($correlationIds->isNotEmpty() && $filteredQuery !== null) {
            $countsByCorrelation = (clone $filteredQuery)
                ->whereIn('correlation_id', $correlationIds)
                ->selectRaw('correlation_id, COUNT(*) as aggregate')
                ->groupBy('correlation_id')
                ->pluck('aggregate', 'correlation_id')
                ->all();
        }

        foreach ($logs as $log) {
            $key = $this->groupKey($log);

            if (str_starts_with($key, self::NO_BATCH_PREFIX)) {
                $this->counts[$key] = 1;

                continue;
            }

            $this->counts[$key] = (int) ($countsByCorrelation[$key] ?? 1);
        }
    }

    public function countFor(DberpAuditLog $record): int
    {
        return $this->counts[$this->groupKey($record)] ?? 1;
    }

    public function scopeQueryByKey(Builder $query, ?string $key): Builder
    {
        if ($key === null) {
            return $query->whereNull('correlation_id');
        }

        if (str_starts_with($key, self::NO_BATCH_PREFIX)) {
            $recordId = (int) substr($key, strlen(self::NO_BATCH_PREFIX));

            return $query->whereKey($recordId);
        }

        return $query->where('correlation_id', $key);
    }

    private function batchLabel(DberpAuditLog $record): string
    {
        if ($record->correlation_id !== null && $record->correlation_id !== '') {
            return substr($record->correlation_id, 0, 8);
        }

        return (string) __('dberp.audit.batch_no_correlation');
    }
}
