<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\BackupDestinationStoreRequest;
use App\Http\Requests\Admin\BackupDestinationUpdateRequest;
use App\Http\Requests\Admin\BackupSettingsUpdateRequest;
use App\Jobs\RunBackupJob;
use App\Models\BackupDestination;
use App\Models\Setting;
use App\Services\Backup\BackupDestinationRegistrar;
use App\Services\Backup\BackupDestinationTester;
use App\Traits\LogsAdminActivity;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class BackupController extends Controller
{
    use LogsAdminActivity;

    public function __construct(
        private BackupDestinationRegistrar $registrar,
        private BackupDestinationTester $tester,
    ) {}

    public function index()
    {
        return view('admin.backups.index', [
            'settings' => [
                'backup_enabled'        => (bool) setting('backup_enabled', false),
                'backup_frequency'      => setting('backup_frequency', 'daily'),
                'backup_time'           => setting('backup_time', '02:00'),
                'backup_retention_days' => (int) setting('backup_retention_days', 14),
                'backup_include_db'     => (bool) setting('backup_include_db', true),
                'backup_include_files'  => (bool) setting('backup_include_files', true),
                'backup_notify'         => (bool) setting('backup_notify', true),
            ],
        ]);
    }

    public function destinationRecords()
    {
        $rows = BackupDestination::query()->latest()->get()->map(fn ($d) => [
            'id'           => $d->id,
            'name'         => $d->name,
            'driver'       => $d->driver,
            'is_enabled'   => $d->is_enabled,
            'last_test_at' => optional($d->last_test_at)->toDateTimeString(),
            'last_test_ok' => $d->last_test_ok,
        ]);

        return response()->json(['data' => $rows]);
    }

    public function storeDestination(BackupDestinationStoreRequest $request)
    {
        $dest = BackupDestination::create($request->validated());
        $this->logCreated(model: $dest, description: "Backup destination created: {$dest->name}");

        return response()->json(['success' => true, 'id' => $dest->id]);
    }

    public function updateDestination(BackupDestinationUpdateRequest $request, BackupDestination $destination)
    {
        $data = $request->validated();
        if (isset($data['config']) && is_array($data['config'])) {
            $incoming = array_filter($data['config'], fn ($v) => $v !== null && $v !== '');
            $data['config'] = array_merge($destination->config ?? [], $incoming);
        }
        $destination->update($data);
        $this->logUpdated(model: $destination, description: "Backup destination updated: {$destination->name}");

        return response()->json(['success' => true]);
    }

    public function destroyDestination(BackupDestination $destination)
    {
        $this->logDeleted(model: $destination, description: "Backup destination deleted: {$destination->name}");
        $destination->delete();

        return response()->json(['success' => true]);
    }

    public function testDestination(BackupDestination $destination)
    {
        $result = $this->tester->testAndRecord($destination);

        return response()->json(['success' => $result['ok'], 'message' => $result['message']]);
    }

    public function backupList()
    {
        $this->registrar->register();
        $disks  = config('backup.backup.destination.disks', []);
        $prefix = config('backup.backup.name');
        $items  = [];

        foreach ($disks as $disk) {
            try {
                foreach (Storage::disk($disk)->files($prefix) as $path) {
                    $items[] = [
                        'disk'          => $disk,
                        'path'          => $path,
                        'name'          => basename($path),
                        'size'          => Storage::disk($disk)->size($path),
                        'last_modified' => Storage::disk($disk)->lastModified($path),
                    ];
                }
            } catch (\Throwable $e) {
                // erişilemeyen hedef atlanır (UI'da hedef testi gösterir)
            }
        }

        usort($items, fn ($a, $b) => $b['last_modified'] <=> $a['last_modified']);

        return response()->json(['data' => $items]);
    }

    public function runBackup()
    {
        RunBackupJob::dispatch();
        $this->logActivity(
            action: self::ACTION_CREATED,
            entityType: 'Backup',
            description: 'Manuel yedekleme başlatıldı'
        );

        return response()->json(['success' => true]);
    }

    public function downloadBackup(Request $request)
    {
        $data = $request->validate([
            'disk' => ['required', 'string'],
            'path' => ['required', 'string'],
        ]);

        $this->registrar->register();
        abort_unless(in_array($data['disk'], config('backup.backup.destination.disks', []), true), 403);

        $prefix = config('backup.backup.name');
        abort_unless(
            $data['path'] === $prefix || str_starts_with($data['path'], $prefix.'/'),
            403
        );

        abort_unless(Storage::disk($data['disk'])->exists($data['path']), 404);

        return Storage::disk($data['disk'])->download($data['path']);
    }

    public function destroyBackup(Request $request)
    {
        $data = $request->validate([
            'disk' => ['required', 'string'],
            'path' => ['required', 'string'],
        ]);

        $this->registrar->register();
        abort_unless(in_array($data['disk'], config('backup.backup.destination.disks', []), true), 403);

        $prefix = config('backup.backup.name');
        abort_unless(
            $data['path'] === $prefix || str_starts_with($data['path'], $prefix.'/'),
            403
        );

        abort_unless(Storage::disk($data['disk'])->exists($data['path']), 404);

        $this->logActivity(
            action: self::ACTION_DELETED,
            entityType: 'Backup',
            description: "Yedek dosyası silindi: {$data['path']}"
        );
        Storage::disk($data['disk'])->delete($data['path']);

        return response()->json(['success' => true]);
    }

    public function updateSettings(BackupSettingsUpdateRequest $request)
    {
        foreach ($request->validated() as $key => $value) {
            Setting::updateOrCreate(
                ['key' => $key, 'group' => 'backup'],
                ['value' => is_bool($value) ? ($value ? '1' : '0') : (string) $value]
            );
        }
        $this->logActivity(
            action: self::ACTION_UPDATED,
            entityType: 'Setting',
            description: 'Yedekleme ayarları güncellendi'
        );

        return response()->json(['success' => true]);
    }
}
