<?php

namespace App\Console\Commands;

use App\Models\Host;
use App\Services\Dns\HetznerDnsClient;
use Illuminate\Console\Command;
use Throwable;

/**
 * Cleans up host DNS records this app published in the PUBLIC Hetzner zone
 * before RegisterHostDns moved to the internal vpn-dns hostsdir — a host's
 * WireGuard address in public DNS hands every scanner the internal subnet.
 *
 * The ids are whatever is still sitting in hosts.dns_record_id (PurgeHost
 * already clears this column for any host removed normally; what remains
 * belongs to hosts that are still active).
 *
 * Never deletes anything on its own: this runs against a live DNS account, a
 * migration is the wrong place to make that call unattended, and a stale id
 * could by now point at a record this app no longer owns. Without --force
 * this only reports what it would remove.
 */
class PruneHostDns extends Command
{
    protected $signature = 'clupilot:prune-host-dns {--force : Actually delete the records}';

    protected $description = 'List (and, with --force, delete) public Hetzner DNS records this app published for a host';

    public function handle(HetznerDnsClient $dns): int
    {
        $hosts = Host::query()->whereNotNull('dns_record_id')->orderBy('name')->get();

        if ($hosts->isEmpty()) {
            $this->info('No host carries a public dns_record_id. Nothing to do.');

            return self::SUCCESS;
        }

        $force = (bool) $this->option('force');
        $failed = 0;

        foreach ($hosts as $host) {
            $label = $host->name !== '' && $host->name !== null ? $host->name : $host->uuid;
            $recordId = $host->dns_record_id;

            if (! $force) {
                $this->line("  would delete  {$label}  record={$recordId}");

                continue;
            }

            try {
                $dns->deleteRecord($recordId);
                $host->update(['dns_record_id' => null]);
                $this->info("  deleted       {$label}  record={$recordId}");
            } catch (Throwable $e) {
                $failed++;
                $this->error("  failed        {$label}  record={$recordId}: {$e->getMessage()}");
            }
        }

        if (! $force) {
            $this->newLine();
            $this->comment(sprintf('Dry run — %d record(s) found, nothing changed. Re-run with --force to delete.', $hosts->count()));

            return self::SUCCESS;
        }

        return $failed === 0 ? self::SUCCESS : self::FAILURE;
    }
}
