<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Domain\Dns\Models\DnsRecord;
use App\Domain\Dns\Models\DnsZone;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

/**
 * Tüm mevcut DNS zone'larının NS kayıtlarını "Sistem Ayarları → DNS" altındaki
 * yeni NS1/NS2 değerleriyle günceller.
 *
 * Kullanım: Admin Sistem Ayarları'ndan NS1/NS2 değişikliğinden sonra çalıştır.
 *
 *   php artisan onox:dns:update-nameservers
 *   php artisan onox:dns:update-nameservers --dry
 */
class UpdateDnsNameserversCommand extends Command
{
    protected $signature = 'onox:dns:update-nameservers
        {--dry : Sadece etkilenecek zone\'ları göster, değişiklik yapma}';

    protected $description = 'Tüm DNS zone\'larının NS kayıtlarını server_settings\'ten okuyup günceller';

    public function handle(): int
    {
        // server_settings'ten NS oku
        $settings = DB::table('server_settings')
            ->whereIn('key', ['dns_ns1', 'dns_ns2', 'dns_ns3', 'dns_ns4'])
            ->pluck('value', 'key');

        $newNs = array_values(array_filter([
            $settings['dns_ns1'] ?? null,
            $settings['dns_ns2'] ?? null,
            $settings['dns_ns3'] ?? null,
            $settings['dns_ns4'] ?? null,
        ]));

        if (empty($newNs)) {
            $this->error('Sistem Ayarları → DNS sekmesinden NS1/NS2 ayarlanmamış.');

            return self::FAILURE;
        }

        $this->info('Yeni NS listesi: ' . implode(', ', $newNs));
        $this->newLine();

        $zones = DnsZone::all();
        $this->info("Toplam {$zones->count()} zone bulundu.");

        $dryRun = (bool) $this->option('dry');
        $updated = 0;
        $unchanged = 0;

        foreach ($zones as $zone) {
            $existing = DnsRecord::where('zone_id', $zone->id)
                ->where('type', 'NS')
                ->where('name', $zone->name)
                ->orderBy('id')
                ->pluck('content')
                ->toArray();

            if ($existing === $newNs) {
                $unchanged++;

                continue;
            }

            $this->line("• {$zone->name}");
            $this->line("    Eski NS: " . (empty($existing) ? '(yok)' : implode(', ', $existing)));
            $this->line("    Yeni NS: " . implode(', ', $newNs));

            if (! $dryRun) {
                // Eski NS kayıtlarını sil
                DnsRecord::where('zone_id', $zone->id)
                    ->where('type', 'NS')
                    ->where('name', $zone->name)
                    ->delete();

                // Yeni NS kayıtlarını ekle
                foreach ($newNs as $ns) {
                    DnsRecord::create([
                        'zone_id' => $zone->id,
                        'name' => $zone->name,
                        'type' => 'NS',
                        'content' => $ns,
                        'ttl' => 3600,
                        'prio' => null,
                        'disabled' => false,
                    ]);
                }

                // SOA içindeki ilk NS'i de güncelle
                $soa = DnsRecord::where('zone_id', $zone->id)
                    ->where('type', 'SOA')
                    ->first();
                if ($soa && ! empty($newNs)) {
                    $parts = preg_split('/\s+/', trim($soa->content));
                    if (count($parts) >= 7) {
                        $parts[0] = $newNs[0]; // İlk NS değiştir
                        $soa->update(['content' => implode(' ', $parts)]);
                    }
                }

                $zone->increment('notified_serial');
            }
            $updated++;
        }

        $this->newLine();
        if ($dryRun) {
            $this->warn("DRY RUN: {$updated} zone güncellenecek, {$unchanged} zone değişmeden kalacak.");
            $this->line('Gerçek güncelleme için --dry parametresi olmadan tekrar çalıştırın.');
        } else {
            $this->info("✓ {$updated} zone güncellendi, {$unchanged} zone değişmeden kaldı.");
        }

        return self::SUCCESS;
    }
}
