<?php

namespace App\Console\Commands;

use App\Models\Mail\MailAccount;
use App\Services\Mail\MailArchiveService;
use Illuminate\Console\Command;

/**
 * Postaları veritabanına yedekler.
 *
 * Senkron yalnızca başlıkları indirir; gövde ve ekler ilk okumada gelir.
 * Bu komut henüz yedeklenmemiş iletilerin ham (RFC 822) hâlini sunucudan
 * çekip sıkıştırarak saklar — dışa aktarma bu kaynaktan üretilir.
 *
 * Zamanlanmış kullanım (gecelik yedek):
 *   php artisan mail:archive --limit=2000
 */
class ArchiveMailMessages extends Command
{
    protected $signature = 'mail:archive
        {--account= : Yalnızca bu hesap kimliği}
        {--limit=500 : Bu çalıştırmada yedeklenecek azami ileti}
        {--force : Yedeği olanları da yeniden indir}';

    protected $description = 'Postaların ham hâlini veritabanına yedekler (dışa aktarma kaynağı)';

    public function handle(MailArchiveService $archives): int
    {
        $accounts = MailAccount::query()
            ->when($this->option('account'), fn ($q) => $q->where('id', (int) $this->option('account')))
            ->where('is_active', true)
            ->orderBy('id')
            ->get();

        if ($accounts->isEmpty()) {
            $this->warn('Yedeklenecek e-posta hesabı bulunamadı.');

            return self::SUCCESS;
        }

        $limit = max(1, (int) $this->option('limit'));
        $force = (bool) $this->option('force');
        $total = ['archived' => 0, 'skipped' => 0, 'failed' => 0, 'bytes' => 0];

        foreach ($accounts as $account) {
            $query = $force
                ? $account->messages()->where('is_deleted', false)->orderBy('id')
                : $archives->pendingQuery($account);

            $messages = $query->limit($limit)->with(['account', 'folder', 'attachments'])->get();

            if ($messages->isEmpty()) {
                $this->line("  {$account->email}: yedeklenecek ileti yok");

                continue;
            }

            $bar = $this->output->createProgressBar($messages->count());
            $bar->setFormat("  {$account->email}: %current%/%max% [%bar%] %percent:3s%%");
            $bar->start();

            $stats = ['archived' => 0, 'skipped' => 0, 'failed' => 0, 'bytes' => 0];
            foreach ($messages as $message) {
                $one = $archives->archiveMany([$message], $force);
                foreach ($stats as $key => $_) {
                    $stats[$key] += $one[$key];
                }
                $bar->advance();
            }

            $bar->finish();
            $this->newLine();

            foreach ($total as $key => $_) {
                $total[$key] += $stats[$key];
            }
        }

        $archives->closeConnections();

        $this->newLine();
        $this->info(sprintf(
            'Yedeklendi: %d · atlandı: %d · başarısız: %d · saklanan: %s',
            $total['archived'], $total['skipped'], $total['failed'], $this->humanBytes($total['bytes'])
        ));

        return self::SUCCESS;
    }

    private function humanBytes(int $bytes): string
    {
        if ($bytes < 1024) {
            return $bytes.' B';
        }
        if ($bytes < 1048576) {
            return round($bytes / 1024, 1).' KB';
        }

        return round($bytes / 1048576, 1).' MB';
    }
}
