<?php

declare(strict_types=1);

namespace App\Http\Controllers\Admin;

use App\Domain\Sysapi\Exceptions\SysapiException;
use App\Domain\Sysapi\Facades\Sysapi;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Inertia\Inertia;
use Inertia\Response;

/**
 * Mail Queue Manager — Postfix postqueue / postsuper bridge.
 *
 * Tüm I/O sysapi üzerinden:
 *   - postqueue-status  (mailq parse)
 *   - postqueue-flush   (postqueue -f)
 *   - postqueue-delete  (postsuper -d)
 *   - postqueue-hold    (postsuper -h)
 *   - postqueue-requeue (postsuper -r)
 *
 * Logs sekmesi (Phase 2): mail_logs DB tablosu doluyorsa o kullanılır;
 * yoksa boş bir liste gönderilir (lazy).
 */
class MailQueueController extends Controller
{
    public function index(Request $request): Response
    {
        $tab = $request->string('tab')->value() ?: 'queue';
        $filter = $request->string('filter')->value() ?: 'all';
        if (! in_array($filter, ['all', 'deferred', 'active', 'hold'], true)) {
            $filter = 'all';
        }

        $queue = [];
        $totals = [
            'queue_size' => 0,
            'active' => 0,
            'deferred' => 0,
            'hold' => 0,
            'bytes' => 0,
        ];
        $sysapiError = null;

        if ($tab === 'queue') {
            try {
                $result = Sysapi::run('postqueue-status', ['filter' => $filter], timeoutSeconds: 30);
                $payload = $result->data ?? [];
                $queue = collect($payload['queue'] ?? [])
                    ->map(fn (array $row) => [
                        'id' => $row['queue_id'] ?? null,
                        'queue_id' => $row['queue_id'] ?? null,
                        'sender' => $row['sender'] ?? '',
                        'recipient' => $row['recipient'] ?? '',
                        'subject' => $row['subject'] ?? '',
                        'size' => (int) ($row['size'] ?? 0),
                        'arrived' => $row['arrival'] ?? '',
                        'reason' => $row['reason'] ?? '',
                        'status' => $row['status'] ?? 'deferred',
                    ])
                    ->all();
                $totals = array_merge($totals, $payload['totals'] ?? []);
            } catch (SysapiException $e) {
                Log::warning('postqueue-status failed', ['err' => $e->getMessage()]);
                $sysapiError = $e->getMessage();
            }
        }

        return Inertia::render('Admin/MailQueue', [
            'tab' => $tab,
            'filter' => $filter,
            'queue' => $queue,
            'logs' => $tab === 'logs' ? $this->fetchLogs() : [],
            'stats' => [
                'queue_size' => $totals['queue_size'] ?? 0,
                'queue_active' => $totals['active'] ?? 0,
                'queue_deferred' => $totals['deferred'] ?? 0,
                'queue_hold' => $totals['hold'] ?? 0,
                'queue_bytes' => $totals['bytes'] ?? 0,
                'sent_today' => $this->countLogsToday('sent'),
                'bounced_today' => $this->countLogsToday('bounced'),
                'rejected_today' => $this->countLogsToday('rejected'),
            ],
            'sysapi_error' => $sysapiError,
            'is_real_sysapi' => Sysapi::isReal(),
        ]);
    }

    public function flush(): RedirectResponse
    {
        try {
            Sysapi::run('postqueue-flush', [], timeoutSeconds: 60);

            return back()->with('success', 'Postfix kuyruğu flush edildi.');
        } catch (SysapiException $e) {
            return back()->with('error', 'Kuyruk flush başarısız: '.$e->getMessage());
        }
    }

    public function deleteMail(string $id): RedirectResponse
    {
        $id = $this->sanitizeQueueId($id);
        if ($id === null) {
            return back()->with('error', 'Geçersiz queue ID.');
        }
        try {
            Sysapi::run('postqueue-delete', ['queue_id' => $id], timeoutSeconds: 15);

            return back()->with('success', "Queue {$id} silindi.");
        } catch (SysapiException $e) {
            return back()->with('error', 'Silme başarısız: '.$e->getMessage());
        }
    }

    public function hold(string $id): RedirectResponse
    {
        $id = $this->sanitizeQueueId($id);
        if ($id === null) {
            return back()->with('error', 'Geçersiz queue ID.');
        }
        try {
            Sysapi::run('postqueue-hold', ['queue_id' => $id], timeoutSeconds: 15);

            return back()->with('success', "Queue {$id} hold edildi.");
        } catch (SysapiException $e) {
            return back()->with('error', 'Hold başarısız: '.$e->getMessage());
        }
    }

    public function requeue(string $id): RedirectResponse
    {
        $id = $this->sanitizeQueueId($id);
        if ($id === null) {
            return back()->with('error', 'Geçersiz queue ID.');
        }
        try {
            Sysapi::run('postqueue-requeue', ['queue_id' => $id], timeoutSeconds: 15);

            return back()->with('success', "Queue {$id} yeniden kuyruğa alındı.");
        } catch (SysapiException $e) {
            return back()->with('error', 'Requeue başarısız: '.$e->getMessage());
        }
    }

    /**
     * Queue ID = "ALL" veya alfanumerik 6-16 karakter.
     */
    private function sanitizeQueueId(string $id): ?string
    {
        $id = trim($id);
        if ($id === 'ALL') {
            return 'ALL';
        }
        if (! preg_match('/^[A-Za-z0-9]{6,16}$/', $id)) {
            return null;
        }

        return $id;
    }

    /**
     * mail_logs tablosu doluysa son 100 girişi döner; boşsa empty.
     * (Tablo Faz E1/E2'de oluşturuluyor — yoksa exception yutulur.)
     *
     * @return array<int, array<string, mixed>>
     */
    private function fetchLogs(): array
    {
        try {
            if (! DB::getSchemaBuilder()->hasTable('mail_logs')) {
                return [];
            }

            return DB::table('mail_logs')
                ->orderByDesc('logged_at')
                ->limit(100)
                ->get()
                ->map(fn ($r) => [
                    'id' => $r->id,
                    'time' => $r->logged_at,
                    'verb' => $r->verb ?? 'sent',
                    'from' => $r->sender ?? '',
                    'to' => $r->recipient ?? '',
                    'subject' => $r->subject ?? '',
                    'size' => (int) ($r->size_bytes ?? 0),
                    'duration_ms' => (int) ($r->duration_ms ?? 0),
                ])
                ->all();
        } catch (\Throwable $e) {
            return [];
        }
    }

    private function countLogsToday(string $verb): int
    {
        try {
            if (! DB::getSchemaBuilder()->hasTable('mail_logs')) {
                return 0;
            }

            return (int) DB::table('mail_logs')
                ->where('verb', $verb)
                ->whereDate('logged_at', now()->toDateString())
                ->count();
        } catch (\Throwable) {
            return 0;
        }
    }
}
