<?php

namespace App\Services\System;

use App\Enums\ActivityEventLabel;
use App\Models\User;
use App\Support\ActivityLog\ModelLabel;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Spatie\Activitylog\Models\Activity;

class ActivityLogService
{
    public function paginateForIndex(array $tableQuery, string $event = '', string $subjectType = ''): LengthAwarePaginator
    {
        $query = Activity::query()
            ->with(['causer.profile'])
            ->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
                $search = $tableQuery['search'];
                $query->where(function (Builder $query) use ($search): void {
                    $query->where('description', 'like', "%{$search}%")
                        ->orWhere('event', 'like', "%{$search}%")
                        ->orWhereHasMorph(
                            'causer',
                            [User::class],
                            fn (Builder $query) => $query
                                ->where('username', 'like', "%{$search}%")
                                ->orWhereHas('profile', fn (Builder $query) => $query->where('full_name', 'like', "%{$search}%")),
                        );
                });
            })
            ->when($event !== '', fn (Builder $query) => $query->where('event', $event))
            ->when($subjectType !== '', fn (Builder $query) => $query->where('subject_type', $subjectType));

        $this->applySorting($query, $tableQuery['sort'], $tableQuery['direction']);

        return $query
            ->paginate(25)
            ->withQueryString()
            ->through(fn (Activity $activity) => [
                'id' => $activity->id,
                'description' => $activity->description,
                'event' => $activity->event,
                'event_label' => ActivityEventLabel::from($activity->event)->label(),
                'subject_type' => $activity->subject_type,
                'subject_label' => ModelLabel::for($activity->subject_type),
                'subject_id' => $activity->subject_id,
                'causer_name' => $activity->causer?->profile?->full_name ?? $activity->causer?->username ?? '-',
                'created_at' => $activity->created_at?->toIso8601String(),
                'created_at_formatted' => $activity->created_at?->translatedFormat('l, d F Y H:i'),
                'changes' => $this->formatChanges($activity->attribute_changes),
            ]);
    }

    private function formatChanges(?Collection $changes): array
    {
        if ($changes === null || $changes->isEmpty()) {
            return [];
        }

        $attributes = $changes->get('attributes', []);
        $old = $changes->get('old', []);

        if (! is_array($attributes)) {
            return [];
        }

        $formatted = [];

        foreach ($attributes as $field => $newValue) {
            $formatted[] = [
                'field' => (string) $field,
                'old' => is_array($old) ? ($old[$field] ?? null) : null,
                'new' => $newValue,
            ];
        }

        return $formatted;
    }

    private function applySorting(Builder $query, string $sort, string $direction): void
    {
        if (in_array($sort, ['created_at', 'description', 'event'], true)) {
            $query->orderBy($sort, $direction);

            return;
        }

        $query->latest();
    }
}
