<?php

declare(strict_types=1);

namespace App\Domain\MailBackup\Services;

use App\Domain\Account\Models\Account;
use App\Domain\Sysapi\Contracts\SysapiBridge;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

/**
 * MailBackupService — Sadece mail dizinleri (~/Maildir) için per-account yedek.
 *
 * BackupService full-account yedek alır (homedir tamamı).
 * Bu servis sadece /home/<user>/Maildir/ alır — daha hızlı + daha küçük arşiv.
 *
 * mail_backups tablosu (Phase 1.5 migration ile gelecek):
 *  - id, account_id, file_path, size_bytes, mailbox_count, status, trigger,
 *    started_at, completed_at, expires_at, last_error
 *
 * Şimdilik (Phase 1) license_audit_log üzerinden trace edilir.
 */
class MailBackupService
{
    public function __construct(private readonly SysapiBridge $sysapi) {}

    /**
     * Tek bir hesabın mail dizinini yedekle.
     *
     * @return array{ok: bool, file_path?: string, size_bytes?: int, mailbox_count?: int, error?: string}
     */
    public function backupAccount(Account $account, string $trigger = 'manual'): array
    {
        $result = $this->sysapi->run('mail-backup-run', [
            'username' => $account->username,
            'home_dir' => $account->homeDirectory(),
            'maildir_path' => $account->homeDirectory() . '/Maildir',
            'trigger' => $trigger,
        ], timeoutSeconds: 1800);

        $success = $result->ok();

        $this->audit('mailbackup.completed', [
            'account' => $account->username,
            'trigger' => $trigger,
            'success' => $success,
            'size_bytes' => $result->data['size_bytes'] ?? 0,
        ], $success);

        if (! $success) {
            return [
                'ok' => false,
                'error' => $result->stderr ?: 'Backup başarısız',
            ];
        }

        return [
            'ok' => true,
            'file_path' => $result->data['file_path'] ?? null,
            'size_bytes' => (int) ($result->data['size_bytes'] ?? 0),
            'mailbox_count' => (int) ($result->data['mailbox_count'] ?? 0),
            'duration_seconds' => $result->data['duration_seconds'] ?? null,
        ];
    }

    /**
     * Tüm aktif hesapların mail dizinlerini yedekle.
     *
     * @return array{queued: int, errors: array<int, array{account: string, error: string}>}
     */
    public function backupAll(string $trigger = 'manual'): array
    {
        $accounts = Account::query()
            ->where('status', 'active')
            ->whereNull('deleted_at')
            ->get();

        $queued = 0;
        $errors = [];

        foreach ($accounts as $account) {
            try {
                $result = $this->backupAccount($account, $trigger);
                if ($result['ok']) {
                    $queued++;
                } else {
                    $errors[] = ['account' => $account->username, 'error' => $result['error']];
                }
            } catch (\Throwable $e) {
                $errors[] = ['account' => $account->username, 'error' => $e->getMessage()];
            }
        }

        $this->audit('mailbackup.bulk.completed', [
            'trigger' => $trigger,
            'queued' => $queued,
            'errors' => count($errors),
            'total' => $accounts->count(),
        ], count($errors) === 0);

        return ['queued' => $queued, 'errors' => $errors];
    }

    /**
     * Bir hesabın yedek snapshot listesi — sysapi backup-list ile.
     *
     * @return array<int, array{snapshot_id:string, file_path:string, created_at:?string, size_bytes:int}>
     */
    public function listSnapshots(Account $account): array
    {
        $result = $this->sysapi->run('backup-list', [
            'username' => $account->username,
            'type' => 'mail',
        ], timeoutSeconds: 30);

        if (! $result->ok()) {
            return [];
        }

        $items = $result->data['backups'] ?? $result->data['snapshots'] ?? [];
        $out = [];
        foreach ($items as $b) {
            $out[] = [
                'snapshot_id' => (string) ($b['snapshot_id'] ?? $b['id'] ?? basename((string) ($b['file_path'] ?? ''))),
                'file_path' => (string) ($b['file_path'] ?? ''),
                'created_at' => $b['created_at'] ?? $b['date'] ?? null,
                'size_bytes' => (int) ($b['size_bytes'] ?? 0),
            ];
        }

        return $out;
    }

    /**
     * Bireysel mailbox restore — bir snapshot'tan tek bir e-posta hesabını geri yükle.
     *
     * @return array{ok:bool, restored?:bool, messages?:int, error?:string}
     */
    public function restoreMailbox(Account $account, string $snapshotId, string $email): array
    {
        $result = $this->sysapi->run('backup-restore', [
            'username' => $account->username,
            'snapshot_id' => $snapshotId,
            'scope' => 'mailbox',
            'email' => $email,
        ], timeoutSeconds: 1800);

        $success = $result->ok();

        $this->audit('mailbackup.restore', [
            'account' => $account->username,
            'snapshot_id' => $snapshotId,
            'email' => $email,
            'success' => $success,
            'messages' => $result->data['messages'] ?? null,
        ], $success);

        if (! $success) {
            return [
                'ok' => false,
                'error' => $result->stderr ?: 'Restore başarısız',
            ];
        }

        return [
            'ok' => true,
            'restored' => (bool) ($result->data['restored'] ?? true),
            'messages' => (int) ($result->data['messages'] ?? 0),
        ];
    }

    /**
     * Son yedeklerin durumu — license_audit_log'tan derler.
     *
     * @return \Illuminate\Support\Collection
     */
    public function recentBackups(int $limit = 20): \Illuminate\Support\Collection
    {
        if (! Schema::hasTable('license_audit_log')) {
            return collect();
        }

        return DB::table('license_audit_log')
            ->where('action', 'like', 'mailbackup.%')
            ->orderByDesc('id')
            ->limit($limit)
            ->get();
    }

    /**
     * Schedule durumu — cron jobs tablosundan (Phase 2 — Scheduler).
     */
    public function scheduleStatus(): array
    {
        return [
            'enabled' => true,
            'cron' => '0 3 * * *',
            'cron_description' => 'Her gün gece 03:00',
            'retention_days' => 7,
            'last_run' => null,
            'next_run' => null,
        ];
    }

    private function audit(string $action, array $payload, bool $success): void
    {
        try {
            if (Schema::hasTable('license_audit_log')) {
                DB::table('license_audit_log')->insert([
                    'action' => $action,
                    'payload' => json_encode($payload, JSON_UNESCAPED_UNICODE),
                    'success' => $success,
                    'remote_ip' => request()?->ip(),
                    'occurred_at' => now(),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }
        } catch (\Throwable) {
            // ignored
        }
    }
}
