<?php

namespace App\Services;

use App\Models\AuditLog;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;

class AuditService
{
    public function log(
        string $event,
        ?User $actor,
        ?Model $model = null,
        ?array $before = null,
        ?array $after = null,
        array $metadata = []
    ): AuditLog {
        return AuditLog::create([
            'organization_id' => $actor?->organization_id
                ?? ($model?->getAttribute('organization_id')),
            'user_id' => $actor?->id,
            'event' => $event,
            'auditable_type' => $model ? $model::class : null,
            'auditable_id' => $model?->getKey(),
            'before' => $this->redact($before),
            'after' => $this->redact($after),
            'metadata' => $this->redact($metadata) ?? [],
            'ip_address' => app()->runningInConsole() ? null : request()->ip(),
            'user_agent' => app()->runningInConsole() ? null : request()->userAgent(),
            'created_at' => now(),
        ]);
    }

    private function redact(?array $data): ?array
    {
        if ($data === null) {
            return null;
        }

        $result = [];

        foreach ($data as $key => $value) {
            if (is_string($key) && $this->isSensitiveKey($key)) {
                $result[$key] = '[REDACTED]';

                continue;
            }

            $result[$key] = is_array($value) ? ($this->redact($value) ?? []) : $value;
        }

        return $result;
    }

    private function isSensitiveKey(string $key): bool
    {
        $key = strtolower($key);

        if ($key === 'token_number' || $key === 'current_served_token' || $key === 'last_allocated_token') {
            return false;
        }

        return $key === 'token'
            || str_contains($key, 'password')
            || str_contains($key, 'secret')
            || str_contains($key, 'credential')
            || str_contains($key, 'authorization')
            || str_contains($key, 'private_key')
            || str_contains($key, 'access_token')
            || str_contains($key, 'refresh_token')
            || str_contains($key, 'api_key');
    }
}
