<?php

namespace App\Models\Concerns;

use App\Models\AuditLog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;

trait Auditable
{
    public static function bootAuditable(): void
    {
        static::created(function (Model $model): void {
            self::writeAuditLog($model, 'created');
        });

        static::updated(function (Model $model): void {
            self::writeAuditLog($model, 'updated');
        });

        static::deleted(function (Model $model): void {
            self::writeAuditLog($model, 'deleted');
        });
    }

    protected static function writeAuditLog(Model $model, string $event): void
    {
        if (! config('audit.enabled', true)) {
            return;
        }

        // 避免在執行 migration/seed/queue 等 console 情境下噴大量資料
        if (app()->runningInConsole()) {
            return;
        }

        $actor = self::resolveActor();
        $request = request();

        $sensitive = (array) config('audit.sensitive_keys', []);

        $changes = $event === 'updated' ? $model->getChanges() : [];
        $original = $event === 'updated'
            ? Arr::only($model->getOriginal(), array_keys($changes))
            : [];

        foreach ($sensitive as $key) {
            unset($changes[$key], $original[$key]);
        }

        $payload = [
            'event' => $event,
            'table' => $model->getTable(),
            'primary_key' => $model->getKeyName(),
            'changes' => $changes ?: null,
            'original' => $original ?: null,
        ];

        $requestId = $request?->headers->get('X-Request-Id')
            ?? $request?->headers->get('X-Request-ID')
            ?? (string) Str::uuid();

        AuditLog::create([
            'occurred_at' => now(),
            'actor_type' => $actor['type'],
            'actor_id' => $actor['id'],
            'guard' => $actor['guard'],
            'action' => $event,
            'route_name' => $request?->route()?->getName(),
            'url' => $request?->fullUrl(),
            'method' => $request?->method(),
            'ip' => $request?->ip(),
            'user_agent' => $request?->userAgent(),
            'request_id' => $requestId,
            'subject_type' => $model::class,
            'subject_id' => is_numeric($model->getKey()) ? (int) $model->getKey() : null,
            'status_code' => null,
            'duration_ms' => null,
            'payload' => $payload,
        ]);
    }

    protected static function resolveActor(): array
    {
        foreach (array_keys((array) config('auth.guards', [])) as $guard) {
            if (Auth::guard($guard)->check()) {
                $user = Auth::guard($guard)->user();

                return [
                    'type' => $user ? $user::class : null,
                    'id' => $user?->getAuthIdentifier(),
                    'guard' => $guard,
                ];
            }
        }

        if (Auth::check()) {
            $user = Auth::user();

            return [
                'type' => $user ? $user::class : null,
                'id' => $user?->getAuthIdentifier(),
                'guard' => config('auth.defaults.guard'),
            ];
        }

        return [
            'type' => null,
            'id' => null,
            'guard' => null,
        ];
    }
}
