<?php

namespace App\Services;

use App\Models\Backup;
use App\Models\User;
use App\Models\Website;
use App\Repositories\BackupRepository;
use Illuminate\Support\Facades\Storage;
use Throwable;

class BackupService
{
    public function __construct(
        protected BackupRepository $backups,
        protected AuditLogService $auditLog,
        protected RemoteAgentService $remoteAgent,
    ) {
    }

    public function requestBackup(Website $website, User $user): Backup
    {
        $backup = $this->backups->createForWebsite($website, [
            'initiated_by' => $user->id,
            'type' => 'manual',
            'status' => 'running',
            'storage_disk' => 'local',
            'started_at' => now(),
        ]);

        try {
            $result = $this->remoteAgent->requestBackup($website, $backup);

            if ($result['ok']) {
                $payload = $result['payload'] ?? [];

                $backup->update([
                    'status' => $payload['status'] ?? 'completed',
                    'storage_disk' => $payload['storage_disk'] ?? 'local',
                    'file_path' => $payload['file_path'] ?? null,
                    'checksum' => $payload['checksum'] ?? null,
                    'size_bytes' => $payload['size_bytes'] ?? null,
                    'completed_at' => $payload['completed_at'] ?? now(),
                    'failure_message' => null,
                ]);

                $this->auditLog->record('backup', 'backup.completed', $result['message'], $website, $user, [
                    'backup_id' => $backup->id,
                ]);

                return $backup->fresh();
            }

            $backup->update([
                'status' => 'failed',
                'failure_message' => $result['message'],
            ]);

            $this->auditLog->record('backup', 'backup.failed', $result['message'], $website, $user, [
                'backup_id' => $backup->id,
            ]);
        } catch (Throwable $exception) {
            $backup->update([
                'status' => 'failed',
                'failure_message' => $exception->getMessage(),
            ]);

            $this->auditLog->record('backup', 'backup.failed', 'Backup request failed unexpectedly.', $website, $user, [
                'backup_id' => $backup->id,
                'error' => $exception->getMessage(),
            ]);
        }

        return $backup;
    }

    public function requestRestore(Backup $backup, User $user): array
    {
        $backup->update([
            'status' => 'restoring',
            'restored_at' => null,
        ]);

        $result = $this->remoteAgent->restoreBackup($backup->website, $backup);

        if ($result['ok']) {
            $payload = $result['payload'] ?? [];

            $backup->update([
                'status' => $payload['status'] ?? 'completed',
                'restored_at' => $payload['restored_at'] ?? now(),
                'failure_message' => null,
            ]);

            $this->auditLog->record('backup', 'backup.restore_completed', $result['message'], $backup->website, $user, [
                'backup_id' => $backup->id,
            ]);

            return $result;
        }

        $backup->update([
            'status' => 'failed',
            'failure_message' => $result['message'],
        ]);

        $this->auditLog->record('backup', 'backup.restore_failed', $result['message'], $backup->website, $user, [
            'backup_id' => $backup->id,
        ]);

        return $result;
    }

    public function delete(Backup $backup, User $user): void
    {
        if ($backup->file_path && Storage::disk($backup->storage_disk)->exists($backup->file_path)) {
            Storage::disk($backup->storage_disk)->delete($backup->file_path);
        }

        $website = $backup->website;
        $backupId = $backup->id;
        $backup->delete();

        $this->auditLog->record('backup', 'backup.deleted', "Backup #{$backupId} was deleted for {$website->name}.", $website, $user);
    }
}
