<?php

declare(strict_types=1);

namespace App\Http\Controllers\Admin;

use App\Domain\Mail\Services\PostfixService;
use App\Domain\Sysapi\Exceptions\SysapiException;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response as HttpResponse;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;

/**
 * Admin Postfix Server Configuration.
 *
 * DB'ye yazar (intent) + sysapi üzerinden gerçek /etc/postfix/main.cf yazımı ve
 * servis işlemlerini (reload/restart/test/queue) tetikler.
 */
class PostfixConfigController extends Controller
{
    public function __construct(private readonly PostfixService $postfixService) {}

    public function index(Request $request): Response
    {
        $rows = DB::table('postfix_config')
            ->orderBy('category')
            ->orderBy('key')
            ->get()
            ->map(function (object $row): object {
                $row->enum_values = $row->enum_values
                    ? json_decode($row->enum_values, true)
                    : null;

                return $row;
            });

        $grouped = $rows->groupBy('category');

        $status = [
            'service' => 'active',
            'pid' => 12345,
            'uptime' => '4 days, 2 hours',
            'queue_size' => 42,
            'deferred' => 3,
            'hold' => 0,
            'corrupt' => 0,
            'mail_version' => 'Postfix 3.5.8',
        ];

        $queue = [
            ['queue_id' => 'A1B2C3D4E', 'size_kb' => 12,  'arrival_time' => '2026-05-13 08:00:00', 'sender' => 'noreply@onox.com.tr',   'recipients' => ['user1@example.com'],                         'status' => 'active',   'reason' => null],
            ['queue_id' => 'B2C3D4E5F', 'size_kb' => 8,   'arrival_time' => '2026-05-13 07:45:00', 'sender' => 'admin@onox.com.tr',     'recipients' => ['user2@example.com', 'user3@example.com'],    'status' => 'active',   'reason' => null],
            ['queue_id' => 'C3D4E5F6A', 'size_kb' => 45,  'arrival_time' => '2026-05-13 06:30:00', 'sender' => 'billing@onox.com.tr',   'recipients' => ['customer1@gmail.com'],                       'status' => 'deferred', 'reason' => 'Host or domain name not found'],
            ['queue_id' => 'D4E5F6A7B', 'size_kb' => 3,   'arrival_time' => '2026-05-13 05:15:00', 'sender' => 'support@onox.com.tr',   'recipients' => ['ticket@helpdesk.com'],                       'status' => 'deferred', 'reason' => 'Connection refused'],
            ['queue_id' => 'E5F6A7B8C', 'size_kb' => 120, 'arrival_time' => '2026-05-13 04:00:00', 'sender' => 'no-reply@onox.com.tr',  'recipients' => ['newsletter@example.org'],                    'status' => 'deferred', 'reason' => 'Connection timed out'],
            ['queue_id' => 'F6A7B8C9D', 'size_kb' => 7,   'arrival_time' => '2026-05-12 23:00:00', 'sender' => 'system@onox.com.tr',    'recipients' => ['ops@onox.com.tr'],                           'status' => 'hold',     'reason' => 'Administrator hold'],
            ['queue_id' => 'A7B8C9D0E', 'size_kb' => 22,  'arrival_time' => '2026-05-12 22:30:00', 'sender' => 'abuse@onox.com.tr',     'recipients' => ['report@abuse.ch'],                           'status' => 'hold',     'reason' => 'Spam investigation'],
            ['queue_id' => 'B8C9D0E1F', 'size_kb' => 5,   'arrival_time' => '2026-05-12 20:00:00', 'sender' => 'postmaster@onox.com.tr', 'recipients' => ['bounce@example.net'],                        'status' => 'active',   'reason' => null],
            ['queue_id' => 'C9D0E1F2A', 'size_kb' => 18,  'arrival_time' => '2026-05-12 18:45:00', 'sender' => 'info@onox.com.tr',      'recipients' => ['contact@partner.com', 'cto@partner.com'],    'status' => 'active',   'reason' => null],
            ['queue_id' => 'D0E1F2A3B', 'size_kb' => 9,   'arrival_time' => '2026-05-12 17:00:00', 'sender' => 'monitor@onox.com.tr',   'recipients' => ['alert@pagerduty.com'],                       'status' => 'active',   'reason' => null],
        ];

        return Inertia::render('Admin/Mail/Postfix', compact('grouped', 'status', 'queue'));
    }

    public function update(Request $request): RedirectResponse
    {
        $request->validate([
            'settings' => ['required', 'array'],
        ]);

        $settings = $request->input('settings', []);

        $configRows = DB::table('postfix_config')
            ->get()
            ->keyBy('key');

        foreach ($settings as $key => $value) {
            /** @var object|null $row */
            $row = $configRows->get($key);

            if ($row === null) {
                continue; // ignore unknown keys
            }

            $sanitized = $this->sanitizeValue((string) $row->data_type, $value);

            DB::table('postfix_config')
                ->where('key', $key)
                ->update(['value' => $sanitized, 'updated_at' => now()]);
        }

        // Güncel ayarları sysapi'ye gönder — /etc/postfix/main.cf yaz
        try {
            $allSettings = DB::table('postfix_config')
                ->get()
                ->map(fn ($r) => ['key' => $r->key, 'value' => $r->value ?? ''])
                ->values()
                ->all();

            $this->postfixService->applyConfig($allSettings);

            return back()->with('success', 'Postfix konfigürasyonu güncellendi ve /etc/postfix/main.cf yazıldı.');
        } catch (SysapiException $e) {
            return back()->with('success', 'Postfix konfigürasyonu DB\'ye kaydedildi.')
                ->with('warning', "main.cf yazılamadı: {$e->getMessage()}");
        }
    }

    public function resetToDefaults(Request $request): RedirectResponse
    {
        DB::table('postfix_config')
            ->update([
                'value' => DB::raw('default_value'),
                'updated_at' => now(),
            ]);

        return back()->with('success', 'Postfix konfigürasyonu varsayılan değerlere sıfırlandı.');
    }

    public function exportMainCf(Request $request): HttpResponse
    {
        $rows = DB::table('postfix_config')
            ->orderBy('category')
            ->orderBy('key')
            ->get();

        $grouped = collect($rows)->groupBy('category');

        $categoryLabels = [
            'general' => 'General',
            'networking' => 'Networking',
            'limits' => 'Limits',
            'security' => 'Security',
            'queue' => 'Queue',
            'virtual' => 'Virtual Hosting (MySQL)',
        ];

        $lines = [];
        $lines[] = '# /etc/postfix/main.cf';
        $lines[] = '# Generated by Onoxsoft Hosting Panel';
        $lines[] = '# Exported: '.now()->format('Y-m-d H:i:s');
        $lines[] = '# WARNING: This is a panel export. The mail server integration will write this file directly when active.';
        $lines[] = '';

        foreach ($grouped as $category => $categoryRows) {
            $label = $categoryLabels[$category] ?? ucfirst((string) $category);
            $lines[] = '# ──────────────────────────────────────────────────────────────';
            $lines[] = "# {$label}";
            $lines[] = '# ──────────────────────────────────────────────────────────────';

            foreach ($categoryRows as $row) {
                if ($row->description_tr) {
                    $lines[] = '# '.$row->description_tr;
                }
                $lines[] = $row->key.' = '.($row->value ?? '');
                $lines[] = '';
            }
        }

        $txt = implode("\n", $lines);

        return response($txt)
            ->header('Content-Type', 'text/plain')
            ->header('Content-Disposition', 'attachment; filename="main.cf-export-'.now()->format('Y-m-d').'.txt"');
    }

    public function reload(Request $request): RedirectResponse
    {
        try {
            $result = $this->postfixService->reload();
            $uptime = $result['uptime'] ?? '';
            $msg = $uptime ? "Postfix reload edildi (aktif: {$uptime})." : 'Postfix reload edildi.';

            return back()->with('success', $msg);
        } catch (SysapiException $e) {
            return back()->with('error', "Postfix reload hatası: {$e->getMessage()}");
        }
    }

    public function restart(Request $request): RedirectResponse
    {
        try {
            $result = $this->postfixService->restart();
            $pid = $result['pid'] ?? '';
            $msg = $pid ? "Postfix yeniden başlatıldı (PID: {$pid})." : 'Postfix yeniden başlatıldı.';

            return back()->with('success', $msg);
        } catch (SysapiException $e) {
            return back()->with('error', "Postfix restart hatası: {$e->getMessage()}");
        }
    }

    public function testConfig(Request $request): RedirectResponse
    {
        try {
            $this->postfixService->test();

            return back()->with('success', 'Postfix syntax OK (postfix check + postconf -n başarılı).');
        } catch (SysapiException $e) {
            return back()->with('error', "Postfix config test hatası: {$e->getMessage()}");
        }
    }

    public function flushQueue(Request $request): RedirectResponse
    {
        try {
            $this->postfixService->flushQueue();

            return back()->with('success', 'Kuyruktaki mailler yeniden teslim için tetiklendi (postqueue -f).');
        } catch (SysapiException $e) {
            return back()->with('error', "Kuyruk flush hatası: {$e->getMessage()}");
        }
    }

    public function deleteFromQueue(Request $request, string $queueId): RedirectResponse
    {
        try {
            $this->postfixService->deleteFromQueue($queueId);

            return back()->with('success', "Kuyruk mesajı silindi (postsuper -d {$queueId}).");
        } catch (SysapiException $e) {
            return back()->with('error', "Kuyruk silme hatası: {$e->getMessage()}");
        }
    }

    // ─── Helpers ────────────────────────────────────────────────────────────────

    private function sanitizeValue(string $dataType, mixed $value): string
    {
        $str = (string) $value;

        return match ($dataType) {
            'integer' => (string) (int) filter_var($str, FILTER_VALIDATE_INT, [
                'options' => ['default' => 0],
            ]),

            'boolean' => in_array(strtolower($str), ['1', 'true', 'on', 'yes'], true) ? 'yes' : 'no',

            default => trim($str),
        };
    }
}
