<?php

namespace App\Modules\Admin\Operations\Services;

use App\Modules\Admin\Operations\Models\BackupRun;
use Illuminate\Support\Arr;

final class BackupHealthService
{
    /**
     * @param  array<string, mixed>  $metadata
     */
    public function recordSuccess(string $type, array $metadata = []): BackupRun
    {
        return BackupRun::query()->create([
            'type' => $type,
            'status' => BackupRun::STATUS_SUCCESS,
            'started_at' => Arr::get($metadata, 'started_at'),
            'completed_at' => Arr::get($metadata, 'completed_at') ?? now(),
            'error_message' => null,
            'metadata' => $metadata,
        ]);
    }

    /**
     * @param  array<string, mixed>  $metadata
     */
    public function recordFailure(string $type, string $errorMessage, array $metadata = []): BackupRun
    {
        return BackupRun::query()->create([
            'type' => $type,
            'status' => BackupRun::STATUS_FAILED,
            'started_at' => Arr::get($metadata, 'started_at'),
            'completed_at' => Arr::get($metadata, 'completed_at') ?? now(),
            'error_message' => $errorMessage,
            'metadata' => $metadata,
        ]);
    }

    public function markRestoreVerified(string $type, ?int $backupRunId = null): ?BackupRun
    {
        $q = BackupRun::query()->where('type', $type)->orderByDesc('id');
        if ($backupRunId !== null) {
            $q->whereKey($backupRunId);
        }
        $row = $q->first();
        if ($row === null) {
            return null;
        }
        $row->forceFill(['restore_verified_at' => now()])->save();

        return $row->fresh();
    }

    public function lastSuccessAt(string $type): ?\Illuminate\Support\Carbon
    {
        return BackupRun::query()
            ->where('type', $type)
            ->where('status', BackupRun::STATUS_SUCCESS)
            ->orderByDesc('completed_at')
            ->value('completed_at');
    }

    public function lastRestoreVerifiedAt(string $type): ?\Illuminate\Support\Carbon
    {
        return BackupRun::query()
            ->where('type', $type)
            ->whereNotNull('restore_verified_at')
            ->orderByDesc('restore_verified_at')
            ->value('restore_verified_at');
    }

    /**
     * @return array{ok: bool, reason: ?string, last_success_at: mixed, last_restore_verified_at: mixed}
     */
    public function health(string $type, int $freshnessMinutes): array
    {
        $last = $this->lastSuccessAt($type);
        $verified = $this->lastRestoreVerifiedAt($type);
        if ($last === null) {
            return [
                'ok' => false,
                'reason' => 'missing_backup',
                'last_success_at' => null,
                'last_restore_verified_at' => $verified,
            ];
        }
        if ($last->lt(now()->subMinutes(max(1, $freshnessMinutes)))) {
            return [
                'ok' => false,
                'reason' => 'stale_backup',
                'last_success_at' => $last,
                'last_restore_verified_at' => $verified,
            ];
        }

        return [
            'ok' => true,
            'reason' => null,
            'last_success_at' => $last,
            'last_restore_verified_at' => $verified,
        ];
    }
}

