<?php

declare(strict_types=1);

namespace App\Http\Controllers\Admin;

use App\Domain\MailLogs\Services\MailLogReader;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Inertia\Inertia;
use Inertia\Response;

/**
 * Admin Mail Delivery Reports (WHM Mail Delivery Reports muadili).
 *
 * Veri kaynağı: MailLogReader::parseDeliveryEvents() → `/var/log/maillog` postfix
 * delivery log'larını parse eder (qmgr from + smtp/local to+status eşleştirmesi).
 *
 * Eski Phase 1 `generateMockEntries()` (50 sahte sender/recipient/status) kaldırıldı.
 * Log dosyası yoksa veya boşsa boş liste döner — UI empty state gösterir.
 *
 * Cache: parse 30sn cache'lenir (2MB log dosyasını her request parse etmemek için).
 */
class MailReportsController extends Controller
{
    private const CACHE_KEY = 'mail.delivery.events.v1';
    private const CACHE_TTL_SECONDS = 30;

    public function __construct(private readonly MailLogReader $logReader) {}

    public function index(Request $request): Response
    {
        $entries = $this->loadEvents();
        $filtered = $this->applyFilters($entries, $request);

        usort($filtered, static fn (array $a, array $b): int => strcmp($b['timestamp'], $a['timestamp']));

        $stats = $this->buildStats($filtered);
        $perPage = 25;
        $page = max(1, (int) $request->integer('page', 1));
        $total = count($filtered);
        $items = array_slice($filtered, ($page - 1) * $perPage, $perPage);

        $logInfo = $this->logReader->info('mail');

        return Inertia::render('Admin/MailReports/Index', [
            'entries' => $items,
            'pagination' => [
                'current_page' => $page,
                'per_page' => $perPage,
                'total' => $total,
                'last_page' => max(1, (int) ceil($total / $perPage)),
            ],
            'stats' => $stats,
            'filters' => $request->only(['status', 'from', 'to', 'sender', 'recipient', 'domain', 'page']),
            'log_info' => $logInfo,
            'data_source' => 'postfix-log',
        ]);
    }

    public function export(Request $request): \Illuminate\Http\Response
    {
        $entries = $this->loadEvents();
        $filtered = $this->applyFilters($entries, $request);

        usort($filtered, static fn (array $a, array $b): int => strcmp($b['timestamp'], $a['timestamp']));

        $rows = [];
        $rows[] = implode(',', ['timestamp', 'sender', 'recipient', 'subject', 'status', 'smtp_code', 'smtp_message', 'size_bytes', 'host']);

        foreach ($filtered as $e) {
            $rows[] = implode(',', [
                '"'.$e['timestamp'].'"',
                '"'.$e['sender'].'"',
                '"'.$e['recipient'].'"',
                '"'.str_replace('"', '""', (string) ($e['subject'] ?? '')).'"',
                '"'.$e['status'].'"',
                '"'.$e['smtp_code'].'"',
                '"'.str_replace('"', '""', (string) $e['smtp_message']).'"',
                $e['size_bytes'],
                '"'.$e['host'].'"',
            ]);
        }

        $csv = implode("\n", $rows);

        return response($csv)
            ->header('Content-Type', 'text/csv')
            ->header('Content-Disposition', 'attachment; filename="onox-mail-'.now()->format('Y-m-d').'.csv"');
    }

    /**
     * Postfix queue ID üzerinden mail'i tekrar kuyruğa al (postsuper -r).
     * Route binding string olduğu için pattern: `[A-F0-9]{6,16}`.
     */
    public function requeue(Request $request, string $queueId): RedirectResponse
    {
        if (! preg_match('/^[A-F0-9]{6,16}$/', $queueId)) {
            return back()->with('error', 'Geçersiz Postfix queue ID.');
        }

        try {
            /** @var \App\Domain\Sysapi\Contracts\SysapiBridge $sysapi */
            $sysapi = app(\App\Domain\Sysapi\Contracts\SysapiBridge::class);
            $result = $sysapi->run('postqueue-requeue', ['queue_id' => $queueId], timeoutSeconds: 15);
            if ($result->failed()) {
                return back()->with('error', "Requeue başarısız: {$result->stderr}");
            }
        } catch (\Throwable $e) {
            return back()->with('error', "Sysapi hatası: {$e->getMessage()}");
        }

        Cache::forget(self::CACHE_KEY);
        return back()->with('success', "Mail {$queueId} kuyruğa geri eklendi (postsuper -r).");
    }

    public function delete(Request $request, string $queueId): RedirectResponse
    {
        if (! preg_match('/^[A-F0-9]{6,16}$/', $queueId)) {
            return back()->with('error', 'Geçersiz Postfix queue ID.');
        }

        try {
            /** @var \App\Domain\Sysapi\Contracts\SysapiBridge $sysapi */
            $sysapi = app(\App\Domain\Sysapi\Contracts\SysapiBridge::class);
            $result = $sysapi->run('postqueue-delete', ['queue_id' => $queueId], timeoutSeconds: 15);
            if ($result->failed()) {
                return back()->with('error', "Delete başarısız: {$result->stderr}");
            }
        } catch (\Throwable $e) {
            return back()->with('error', "Sysapi hatası: {$e->getMessage()}");
        }

        Cache::forget(self::CACHE_KEY);
        return back()->with('success', "Mail {$queueId} kuyruktan silindi.");
    }

    /**
     * Postfix log parse — 30sn cache'li.
     * @return array<int, array<string, mixed>>
     */
    private function loadEvents(): array
    {
        return Cache::remember(self::CACHE_KEY, self::CACHE_TTL_SECONDS, function () {
            return $this->logReader->parseDeliveryEvents(limit: 500);
        });
    }

    /** @param array<int, array<string, mixed>> $entries */
    private function applyFilters(array $entries, Request $request): array
    {
        $status = $request->input('status', 'all');
        $sender = (string) $request->input('sender', '');
        $recipient = (string) $request->input('recipient', '');
        $domain = (string) $request->input('domain', '');
        $from = $request->input('from');
        $to = $request->input('to');

        return array_values(array_filter($entries, static function (array $e) use ($status, $sender, $recipient, $domain, $from, $to): bool {
            if ($status !== 'all' && $status !== '' && $e['status'] !== $status) {
                return false;
            }
            if ($sender !== '' && ! str_contains(strtolower($e['sender']), strtolower($sender))) {
                return false;
            }
            if ($recipient !== '' && ! str_contains(strtolower($e['recipient']), strtolower($recipient))) {
                return false;
            }
            if ($domain !== '') {
                $domainLower = strtolower($domain);
                $senderDomain = strtolower((string) substr((string) strstr($e['sender'], '@'), 1));
                $recipientDomain = strtolower((string) substr((string) strstr($e['recipient'], '@'), 1));
                if (! str_contains($senderDomain, $domainLower) && ! str_contains($recipientDomain, $domainLower)) {
                    return false;
                }
            }
            if ($from !== null && $from !== '') {
                try {
                    $fromDate = Carbon::parse($from)->startOfDay();
                    if (Carbon::parse($e['timestamp'])->lt($fromDate)) {
                        return false;
                    }
                } catch (\Throwable) {
                    // ignore invalid date
                }
            }
            if ($to !== null && $to !== '') {
                try {
                    $toDate = Carbon::parse($to)->endOfDay();
                    if (Carbon::parse($e['timestamp'])->gt($toDate)) {
                        return false;
                    }
                } catch (\Throwable) {
                    // ignore invalid date
                }
            }
            return true;
        }));
    }

    /** @param array<int, array<string, mixed>> $filtered */
    private function buildStats(array $filtered): array
    {
        $stats = ['delivered' => 0, 'sent' => 0, 'deferred' => 0, 'bounced' => 0, 'rejected' => 0, 'total' => count($filtered)];
        foreach ($filtered as $e) {
            if (isset($stats[$e['status']])) {
                $stats[$e['status']]++;
            }
        }
        return $stats;
    }
}
