<?php

namespace App\Services\Dns;

use RuntimeException;

/**
 * Hands out the same `{name}/{type}` ids as the real client and refuses the
 * same fqdns — see RrsetId. A fake that answered `rec-1` would let every test
 * that purges a host or prunes a legacy record go green over a teardown that
 * throws in production.
 */
class FakeHetznerDnsClient implements HetznerDnsClient
{
    /** @var array<string, string> fqdn => rrset id */
    public array $records = [];

    /** @var array<string, string> fqdn => published value — without this a test
     *  cannot tell which address ended up in DNS, which is the whole point for
     *  host records. */
    public array $values = [];

    public bool $failUpsert = false;

    public bool $failDelete = false;

    public function upsertRecord(string $fqdn, string $type, string $value): string
    {
        if ($this->failUpsert) {
            throw new RuntimeException('hetzner dns 5xx');
        }

        // Derived, not counted: the id a caller stores has to be the one the
        // real client would store, or the round trip through deleteRecord()
        // below proves nothing about the round trip in production.
        $id = RrsetId::for($fqdn, $type);

        $this->values[$fqdn] = $value;

        return $this->records[$fqdn] = $id;
    }

    public function deleteRecord(string $recordId): void
    {
        if ($this->failDelete) {
            throw new RuntimeException('hetzner dns 5xx');
        }

        // Lets a legacy id pass exactly like the real client does — a host
        // carrying one has to stay purgeable, and a fake that threw here would
        // prove the opposite of what the real client does.
        if (! RrsetId::isRrsetId($recordId)) {
            return;
        }

        $this->records = array_filter($this->records, fn ($id) => $id !== $recordId);
    }
}
