<?php

declare(strict_types=1);

namespace App\Http\Controllers\Admin;

use App\Domain\Dns\Models\DnsTemplate;
use App\Domain\Dns\Models\DnsTemplateRecord;
use App\Domain\Dns\Services\DnsTemplateApplier;
use App\Domain\Package\Models\Package;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Inertia\Inertia;
use Inertia\Response;

/**
 * Admin → DNS → Şablonlar.
 *
 * WHM "DNS Zone Template" muadili — admin yeniden kullanılabilir DNS kayıt
 * setleri tanımlar (örn: "WordPress", "Google Workspace"). Bu şablonlar yeni
 * zone yaratılırken DnsTemplateApplier tarafından çözülür ve uygulanır.
 *
 * Routes: admin.dns.templates.* (web.php'ye ekle)
 */
class DnsTemplateController extends Controller
{
    private const RECORD_TYPES = ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'SRV', 'CAA', 'NS'];

    public function __construct(private readonly DnsTemplateApplier $applier) {}

    public function index(): Response
    {
        $templates = DnsTemplate::with(['package:id,name,slug'])
            ->withCount('records')
            ->orderByDesc('is_default')
            ->orderBy('name')
            ->get()
            ->map(fn (DnsTemplate $t) => [
                'id' => $t->id,
                'name' => $t->name,
                'slug' => $t->slug,
                'description' => $t->description,
                'is_default' => $t->is_default,
                'is_active' => $t->is_active,
                'records_count' => $t->records_count,
                'package' => $t->package ? [
                    'id' => $t->package->id,
                    'name' => $t->package->name,
                    'slug' => $t->package->slug,
                ] : null,
                'placeholders' => $t->placeholders,
                'created_at' => optional($t->created_at)->toIso8601String(),
                'updated_at' => optional($t->updated_at)->toIso8601String(),
            ]);

        $stats = [
            'total' => $templates->count(),
            'active' => $templates->where('is_active', true)->count(),
            'has_default' => $templates->where('is_default', true)->count() > 0,
        ];

        return Inertia::render('Admin/Dns/Templates/Index', [
            'templates' => $templates,
            'packages' => Package::query()->orderBy('name')->get(['id', 'name', 'slug']),
            'stats' => $stats,
        ]);
    }

    public function show(int $id): Response
    {
        $template = DnsTemplate::with(['records', 'package:id,name,slug'])->findOrFail($id);

        return Inertia::render('Admin/Dns/Templates/Show', [
            'template' => [
                'id' => $template->id,
                'name' => $template->name,
                'slug' => $template->slug,
                'description' => $template->description,
                'is_default' => $template->is_default,
                'is_active' => $template->is_active,
                'applies_to_package_id' => $template->applies_to_package_id,
                'placeholders' => $template->placeholders ?? [],
                'package' => $template->package ? [
                    'id' => $template->package->id,
                    'name' => $template->package->name,
                    'slug' => $template->package->slug,
                ] : null,
                'records' => $template->records->map(fn (DnsTemplateRecord $r) => [
                    'id' => $r->id,
                    'name' => $r->name,
                    'type' => $r->type,
                    'content' => $r->content,
                    'ttl' => $r->ttl,
                    'prio' => $r->prio,
                    'sort_order' => $r->sort_order,
                ])->values(),
                'created_at' => optional($template->created_at)->toIso8601String(),
            ],
            'packages' => Package::query()->orderBy('name')->get(['id', 'name', 'slug']),
            'record_types' => self::RECORD_TYPES,
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $this->validateTemplate($request);

        $tpl = DB::transaction(function () use ($validated, $request) {
            $tpl = DnsTemplate::create([
                'name' => $validated['name'],
                'slug' => $validated['slug'],
                'description' => $validated['description'] ?? null,
                'is_default' => false, // setDefault ayrı endpoint
                'is_active' => $validated['is_active'] ?? true,
                'applies_to_package_id' => $validated['applies_to_package_id'] ?? null,
                'placeholders' => $validated['placeholders'] ?? [],
                'created_by' => $request->user()?->id,
            ]);

            return $tpl;
        });

        return redirect()->route('admin.dns.templates.show', $tpl->id)
            ->with('success', "Şablon oluşturuldu: {$tpl->name}");
    }

    public function update(Request $request, int $id): RedirectResponse
    {
        $tpl = DnsTemplate::findOrFail($id);
        $validated = $this->validateTemplate($request, $tpl->id);

        $tpl->update([
            'name' => $validated['name'],
            'slug' => $validated['slug'],
            'description' => $validated['description'] ?? null,
            'is_active' => $validated['is_active'] ?? $tpl->is_active,
            'applies_to_package_id' => $validated['applies_to_package_id'] ?? null,
            'placeholders' => $validated['placeholders'] ?? [],
        ]);

        return back()->with('success', "Şablon güncellendi: {$tpl->name}");
    }

    public function destroy(int $id): RedirectResponse
    {
        $tpl = DnsTemplate::findOrFail($id);

        if ($tpl->is_default) {
            return back()->with('error', 'Varsayılan şablon silinemez. Önce başka bir şablonu varsayılan yapın.');
        }

        $name = $tpl->name;
        $tpl->delete();

        return redirect()->route('admin.dns.templates.index')
            ->with('success', "Şablon silindi: {$name}");
    }

    /**
     * Bu şablonu global varsayılan yap — atomik.
     */
    public function setDefault(int $id): RedirectResponse
    {
        $tpl = DnsTemplate::findOrFail($id);

        DB::transaction(function () use ($tpl) {
            DnsTemplate::where('is_default', true)
                ->where('id', '!=', $tpl->id)
                ->update(['is_default' => false]);

            $tpl->update(['is_default' => true, 'is_active' => true]);
        });

        return back()->with('success', "Varsayılan şablon: {$tpl->name}");
    }

    // ─── Records ──────────────────────────────────────────────────────────

    public function storeRecord(Request $request, int $templateId): RedirectResponse
    {
        $tpl = DnsTemplate::findOrFail($templateId);
        $validated = $this->validateRecord($request);

        DnsTemplateRecord::create([
            'dns_template_id' => $tpl->id,
            'name' => $validated['name'],
            'type' => $validated['type'],
            'content' => $validated['content'],
            'ttl' => $validated['ttl'] ?? 3600,
            'prio' => $validated['prio'] ?? null,
            'sort_order' => $validated['sort_order'] ?? ($tpl->records()->max('sort_order') + 1),
        ]);

        return back()->with('success', 'Kayıt eklendi.');
    }

    public function updateRecord(Request $request, int $templateId, int $recordId): RedirectResponse
    {
        $tpl = DnsTemplate::findOrFail($templateId);
        $record = DnsTemplateRecord::where('dns_template_id', $tpl->id)
            ->where('id', $recordId)
            ->firstOrFail();

        $validated = $this->validateRecord($request);
        $record->update([
            'name' => $validated['name'],
            'type' => $validated['type'],
            'content' => $validated['content'],
            'ttl' => $validated['ttl'] ?? 3600,
            'prio' => $validated['prio'] ?? null,
            'sort_order' => $validated['sort_order'] ?? $record->sort_order,
        ]);

        return back()->with('success', 'Kayıt güncellendi.');
    }

    public function destroyRecord(int $templateId, int $recordId): RedirectResponse
    {
        $record = DnsTemplateRecord::where('dns_template_id', $templateId)
            ->where('id', $recordId)
            ->firstOrFail();

        $record->delete();

        return back()->with('success', 'Kayıt silindi.');
    }

    /**
     * Şablonu örnek domain ile ön-izle — DB'ye yazmaz.
     * Body: { domain: "example.com", server_ip?: string, mail_host?: string, ... }
     */
    public function preview(Request $request, int $id): JsonResponse
    {
        $tpl = DnsTemplate::with('records')->findOrFail($id);

        $validated = $request->validate([
            'domain' => ['required', 'string', 'regex:/^[a-z0-9.-]+\.[a-z]{2,}$/i'],
            'server_ip' => ['nullable', 'ip'],
            'mail_host' => ['nullable', 'string', 'max:253'],
        ]);

        $context = array_filter([
            'server_ip' => $validated['server_ip'] ?? null,
            'mail_host' => $validated['mail_host'] ?? null,
        ], fn ($v) => $v !== null);

        $records = $this->applier->preview($tpl, strtolower($validated['domain']), $context);

        return response()->json([
            'domain' => $validated['domain'],
            'records' => $records,
            'count' => count($records),
        ]);
    }

    // ─── Validation helpers ───────────────────────────────────────────────

    private function validateTemplate(Request $request, ?int $ignoreId = null): array
    {
        $slugIgnore = $ignoreId ? ",{$ignoreId}" : '';

        return $request->validate([
            'name' => ['required', 'string', 'max:120', "unique:dns_templates,name{$slugIgnore}"],
            'slug' => ['required', 'string', 'max:120', 'regex:/^[a-z0-9]+(-[a-z0-9]+)*$/', "unique:dns_templates,slug{$slugIgnore}"],
            'description' => ['nullable', 'string', 'max:2000'],
            'is_active' => ['nullable', 'boolean'],
            'applies_to_package_id' => ['nullable', 'integer', 'exists:packages,id'],
            'placeholders' => ['nullable', 'array'],
            'placeholders.*' => ['nullable'],
        ]);
    }

    private function validateRecord(Request $request): array
    {
        return $request->validate([
            'name' => ['required', 'string', 'max:253'],
            'type' => ['required', 'string', 'in:' . implode(',', self::RECORD_TYPES)],
            'content' => ['required', 'string', 'max:1024'],
            'ttl' => ['nullable', 'integer', 'min:60', 'max:604800'],
            'prio' => ['nullable', 'integer', 'min:0', 'max:65535'],
            'sort_order' => ['nullable', 'integer', 'min:0'],
        ]);
    }
}
