<?php

namespace App\Modules\Admin\Operations\Services;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Storage;

final class DeploymentReadinessService
{
    public function __construct(
        private readonly BackupHealthService $backups,
    ) {}

    /**
     * @return array{ok: bool, checks: array<int, array{key: string, ok: bool, detail: ?string}>}
     */
    public function evaluate(): array
    {
        $checks = [
            $this->checkStorageWritable(),
            $this->checkDatabaseReachable(),
            $this->checkBackupFreshness(),
            $this->checkQueueBacklog(),
        ];

        $ok = collect($checks)->every(fn ($c) => (bool) ($c['ok'] ?? false));

        return ['ok' => $ok, 'checks' => $checks];
    }

    /**
     * @return array{key: string, ok: bool, detail: ?string}
     */
    private function checkStorageWritable(): array
    {
        try {
            $disk = Storage::disk('local');
            $path = 'ops/healthcheck-'.uniqid('', true).'.txt';
            $disk->put($path, 'ok');
            $disk->delete($path);

            return ['key' => 'storage_writable', 'ok' => true, 'detail' => null];
        } catch (\Throwable $e) {
            return ['key' => 'storage_writable', 'ok' => false, 'detail' => $e->getMessage()];
        }
    }

    /**
     * @return array{key: string, ok: bool, detail: ?string}
     */
    private function checkDatabaseReachable(): array
    {
        try {
            DB::select('select 1');

            return ['key' => 'db_reachable', 'ok' => true, 'detail' => null];
        } catch (\Throwable $e) {
            return ['key' => 'db_reachable', 'ok' => false, 'detail' => $e->getMessage()];
        }
    }

    /**
     * @return array{key: string, ok: bool, detail: ?string}
     */
    private function checkBackupFreshness(): array
    {
        $mins = (int) config('operations.backup_freshness_minutes', 1440);
        $db = $this->backups->health(\App\Modules\Admin\Operations\Models\BackupRun::TYPE_DB, $mins);
        $files = $this->backups->health(\App\Modules\Admin\Operations\Models\BackupRun::TYPE_FILES, $mins);
        $ok = (bool) $db['ok'] && (bool) $files['ok'];
        $detail = $ok ? null : 'db='.(string) ($db['reason'] ?? '').', files='.(string) ($files['reason'] ?? '');

        return ['key' => 'backup_fresh', 'ok' => $ok, 'detail' => $detail];
    }

    /**
     * @return array{key: string, ok: bool, detail: ?string}
     */
    private function checkQueueBacklog(): array
    {
        if (! Schema::hasTable('jobs')) {
            return ['key' => 'queue_backlog', 'ok' => true, 'detail' => 'no_jobs_table'];
        }
        $warn = (int) config('operations.queue_backlog_warn', 500);
        $count = (int) DB::table('jobs')->count();
        $ok = $count <= $warn;

        return ['key' => 'queue_backlog', 'ok' => $ok, 'detail' => 'count='.$count.', warn='.$warn];
    }
}

