<?php

namespace App\Modules\Registrar\Resellal;

use App\Core\Registrar\AbstractRegistrar;
use Illuminate\Support\Facades\Log;

/**
 * Resell.al domain registrar module.
 *
 * Referans (birebir): HostBill class.resell_al.php — Resell.al gerçek API'si
 * JSON-RPC 2.0'dır (REST DEĞİL): tek endpoint `http://api.resell.al/server.php`,
 * her istek `{"method": "<Method>", "params": [{...}], "id": <n>}` gövdesiyle
 * POST edilir; yanıt `result`/`error` anahtarlarından okunur. Kimlik doğrulama
 * her `params` objesine gömülen `Username`/`Password` iledir (Bearer token YOK).
 *
 * Desteklenen JSON-RPC komutları (referans `$commands` + yardımcılar):
 *   RegisterDomain, TransferDomain, RenewDomain, CheckDomain, ListDomains,
 *   ListNameservers, UpdateDomainNS, DisplayDomainContacts, EditDomainContacts.
 *
 * Referansta KARŞILIĞI OLMAYAN operasyonlar (EPP code, domain lock, pricing,
 * child-NS, WHOIS privacy, domain suggestion) dürüstçe "desteklenmiyor" döner —
 * uydurma endpoint + sahte-success YASAK.
 */
class Resellal extends AbstractRegistrar
{
    /**
     * Resell.al JSON-RPC endpoint (referans birebir).
     */
    protected string $apiUrl = 'http://api.resell.al/server.php';

    /**
     * JSON-RPC request id sayacı.
     */
    protected int $rpcId = 1;

    // -------------------------------------------------------------------------
    //  Configuration
    // -------------------------------------------------------------------------

    /**
     * Module configuration fields — referans: Username + Password.
     */
    public function getConfigFields(): array
    {
        return [
            'username' => [
                'type' => 'text',
                'label' => __('admin/modules.resellal_field_username_label'),
                'required' => true,
                'description' => __('admin/modules.resellal_field_username_description'),
                'value' => $this->config['username'] ?? '',
            ],
            'password' => [
                'type' => 'password',
                'label' => __('admin/modules.resellal_field_password_label'),
                'required' => true,
                'description' => __('admin/modules.resellal_field_password_description'),
                'placeholder' => '********',
                'value' => $this->config['password'] ?? '',
            ],
        ];
    }

    /**
     * Validate module configuration.
     */
    public function validateConfig()
    {
        if (empty($this->config['username']) || empty($this->config['password'])) {
            throw new \Exception(__('admin/modules.resellal_config_credentials_missing'));
        }

        return true;
    }

    // -------------------------------------------------------------------------
    //  API Communication (JSON-RPC)
    // -------------------------------------------------------------------------

    /**
     * Resell.al JSON-RPC çağrısı yap.
     *
     * Referans jsonRPCClient: `{"method": <method>, "params": [<paramsObj>], "id": <id>}`
     * gövdesiyle POST; yanıt `result` (başarı) / `error` (hata) anahtarlarından
     * okunur. Username/Password çağıran tarafından `$rpcParams`'a gömülür.
     *
     * @param  string  $method  JSON-RPC metod adı (ör. RegisterDomain)
     * @param  array  $rpcParams  Metod parametreleri (Username/Password DAHİL)
     * @return array status/message/data zarfı
     */
    protected function rpcCall(string $method, array $rpcParams): array
    {
        $id = $this->rpcId++;

        $request = [
            'method' => $method,
            'params' => [$rpcParams],
            'id' => $id,
        ];

        // Secret loglanmaz — yalnız metod adı.
        Log::debug('Resellal JSON-RPC request', ['method' => $method]);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->apiUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Accept: application/json',
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request));

        $response = curl_exec($ch);
        $curlError = curl_error($ch);
        $curlErrno = curl_errno($ch);
        curl_close($ch);

        if ($curlErrno || $response === false || $response === '') {
            Log::error('Resellal: cURL error', ['errno' => $curlErrno, 'error' => $curlError]);

            return $this->errorResponse(
                __('admin/modules.resellal_curl_error', ['error' => $curlError ?: 'No response'])
            );
        }

        $decoded = json_decode($response, true);

        if (json_last_error() !== JSON_ERROR_NONE || ! is_array($decoded)) {
            Log::error('Resellal: Invalid JSON-RPC response', ['response' => substr((string) $response, 0, 500)]);

            return $this->errorResponse(__('admin/modules.resellal_invalid_response'));
        }

        // JSON-RPC hata sözleşmesi: `error` null değilse başarısız (fail-closed).
        if (isset($decoded['error']) && $decoded['error'] !== null) {
            $err = $decoded['error'];
            $errorMessage = is_array($err)
                ? ($err['message'] ?? json_encode($err))
                : (string) $err;
            Log::error('Resellal: API error', ['method' => $method, 'message' => $errorMessage]);

            return $this->errorResponse($errorMessage);
        }

        return [
            'status' => 'success',
            'data' => $decoded['result'] ?? [],
        ];
    }

    /**
     * Username/Password kimlik alanlarını üretir (her RPC çağrısına eklenir).
     *
     * @return array{Username:string,Password:string}
     */
    protected function authParams(): array
    {
        return [
            'Username' => (string) ($this->config['username'] ?? ''),
            'Password' => (string) ($this->config['password'] ?? ''),
        ];
    }

    /**
     * Domain adından sld/tld çıkar. Module-is-Truth: TLD domain-adından türetilir
     * ($params['sld']/$params['tld'] builder'dan gelir; yoksa domain'den split).
     *
     * @return array{sld:string,tld:string}
     */
    protected function splitDomain(array $params): array
    {
        $sld = $params['sld'] ?? '';
        $tld = $params['tld'] ?? '';

        if ($sld === '' || $tld === '') {
            $domain = (string) ($params['domain'] ?? '');
            $parts = explode('.', $domain, 2);
            $sld = $sld !== '' ? $sld : ($parts[0] ?? '');
            $tld = $tld !== '' ? $tld : ($parts[1] ?? '');
        }

        return ['sld' => $sld, 'tld' => ltrim((string) $tld, '.')];
    }

    // -------------------------------------------------------------------------
    //  Response Helpers
    // -------------------------------------------------------------------------

    /**
     * Build a standard success response.
     */
    protected function successResponse(string $message, array $data = []): array
    {
        return [
            'status' => 'success',
            'message' => $message,
            'data' => $data,
        ];
    }

    /**
     * Build a standard error response.
     */
    protected function errorResponse(string $message, array $data = []): array
    {
        return [
            'status' => 'error',
            'message' => $message,
            'data' => $data,
        ];
    }

    // -------------------------------------------------------------------------
    //  Domain Registration — referans Register() → RegisterDomain
    // -------------------------------------------------------------------------

    /**
     * Register a new domain.
     * JSON-RPC: RegisterDomain (tld, sld, regperiod, ns1..ns5, contact flat).
     */
    public function registerDomain(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $regperiod = (int) ($params['period'] ?? $params['years'] ?? 1);

            $rpcParams = array_merge($this->authParams(), [
                'tld' => $tld,
                'sld' => $sld,
                'regperiod' => $regperiod,
            ]);

            // Referans: ns1..ns5 düz anahtar. Builder `nameservers` dizisi verir.
            $rpcParams = array_merge($rpcParams, $this->nameserverFields($params, 5));

            // PRC-969: registrant contact kanonik helper'dan → BOŞ gitmez.
            $rpcParams = array_merge($rpcParams, $this->contactFields($params, 'registrant'));

            $result = $this->rpcCall('RegisterDomain', $rpcParams);
            if ($result['status'] !== 'success') {
                return $result;
            }

            Log::info('Resellal: Domain registered', ['domain' => $sld . '.' . $tld]);

            return $this->successResponse(__('admin/modules.resellal_register_success'), [
                'domain' => $sld . '.' . $tld,
                'period' => $regperiod,
                'registered_at' => now()->toISOString(),
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Register domain error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    // -------------------------------------------------------------------------
    //  Domain Transfer — referans Transfer() → TransferDomain
    // -------------------------------------------------------------------------

    /**
     * Transfer a domain.
     * JSON-RPC: TransferDomain (tld, sld, contact flat, eppcode).
     */
    public function transferDomain(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $eppCode = $params['epp_code'] ?? $params['auth_code'] ?? '';
            if (trim((string) $eppCode) === '') {
                return $this->errorResponse(__('admin/modules.resellal_auth_code_required'));
            }

            $rpcParams = array_merge($this->authParams(), [
                'tld' => $tld,
                'sld' => $sld,
            ]);

            // PRC-969: transfer yönünde de registrant contact kanonik helper'dan.
            $rpcParams = array_merge($rpcParams, $this->contactFields($params, 'registrant'));

            // Referans: `eppcode` düz anahtar.
            $rpcParams['eppcode'] = (string) $eppCode;

            $result = $this->rpcCall('TransferDomain', $rpcParams);
            if ($result['status'] !== 'success') {
                return $result;
            }

            Log::info('Resellal: Domain transfer initiated', ['domain' => $sld . '.' . $tld]);

            return $this->successResponse(__('admin/modules.resellal_transfer_success'), [
                'domain' => $sld . '.' . $tld,
                'transfer_started_at' => now()->toISOString(),
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Transfer domain error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    // -------------------------------------------------------------------------
    //  Domain Renewal — referans Renew() → RenewDomain
    // -------------------------------------------------------------------------

    /**
     * Renew a domain.
     * JSON-RPC: RenewDomain (tld, sld, regperiod).
     */
    public function renewDomain(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $regperiod = (int) ($params['period'] ?? $params['years'] ?? $params['numyears'] ?? 1);

            $rpcParams = array_merge($this->authParams(), [
                'tld' => $tld,
                'sld' => $sld,
                'regperiod' => $regperiod,
            ]);

            $result = $this->rpcCall('RenewDomain', $rpcParams);
            if ($result['status'] !== 'success') {
                return $result;
            }

            Log::info('Resellal: Domain renewed', ['domain' => $sld . '.' . $tld]);

            return $this->successResponse(__('admin/modules.resellal_renew_success'), [
                'domain' => $sld . '.' . $tld,
                'period' => $regperiod,
                'renewed_at' => now()->toISOString(),
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Renew domain error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    // -------------------------------------------------------------------------
    //  Nameservers — referans updateNameServers()/getNameServers()
    // -------------------------------------------------------------------------

    /**
     * Set nameservers for a domain.
     * JSON-RPC: UpdateDomainNS (sld, tld, ns1..ns4).
     */
    public function setNameservers(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $nameservers = array_values(array_filter($params['nameservers'] ?? []));
            if (count($nameservers) < 2) {
                return $this->errorResponse(__('admin/modules.resellal_min_nameservers'));
            }

            $rpcParams = array_merge($this->authParams(), [
                'sld' => $sld,
                'tld' => $tld,
            ]);

            // Referans: ns1..ns4 düz anahtar.
            $rpcParams = array_merge($rpcParams, $this->nameserverFields($params, 4));

            $result = $this->rpcCall('UpdateDomainNS', $rpcParams);
            if ($result['status'] !== 'success') {
                return $result;
            }

            return $this->successResponse(__('admin/modules.resellal_nameservers_updated'), [
                'domain' => $sld . '.' . $tld,
                'nameservers' => $nameservers,
                'updated_at' => now()->toISOString(),
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Set nameservers error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    /**
     * Get nameservers for a domain.
     * JSON-RPC: ListNameservers (tld, sld).
     */
    public function getNameservers(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $rpcParams = array_merge($this->authParams(), [
                'tld' => $tld,
                'sld' => $sld,
            ]);

            $result = $this->rpcCall('ListNameservers', $rpcParams);
            if ($result['status'] !== 'success') {
                return $result;
            }

            $nameservers = $this->extractNameservers($result['data']);

            return $this->successResponse(__('admin/modules.resellal_nameservers_retrieved'), [
                'domain' => $sld . '.' . $tld,
                'nameservers' => $nameservers,
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Get nameservers error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    // -------------------------------------------------------------------------
    //  Contact Details — referans updateContactInfo()/getContactInfo()
    // -------------------------------------------------------------------------

    /**
     * Set contact details for a domain.
     * JSON-RPC: EditDomainContacts (tld, sld, contact flat).
     */
    public function setContactDetails(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $rpcParams = array_merge($this->authParams(), [
                'tld' => $tld,
                'sld' => $sld,
            ]);

            // Round-trip (#4): modifyContact akışı `groups` verirse (module-authored
            // alan adları, Registrant/Admin/... anahtarlı) registrant grubunu OLDUĞU
            // GİBİ geçir — kanonik şekille merge etme. Referans tek düz contact seti
            // kabul eder (registrant); grup yoksa kanonik helper'dan çek.
            $groups = $params['groups'] ?? [];
            if (! empty($groups) && is_array($groups)) {
                $rpcParams = array_merge($rpcParams, $this->flatFromModifyGroup($groups));
            } else {
                $rpcParams = array_merge($rpcParams, $this->contactFields($params, 'registrant'));
            }

            $result = $this->rpcCall('EditDomainContacts', $rpcParams);
            if ($result['status'] !== 'success') {
                return $result;
            }

            return $this->successResponse(__('admin/modules.resellal_contacts_updated'), [
                'domain' => $sld . '.' . $tld,
                'updated_at' => now()->toISOString(),
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Set contacts error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    /**
     * Get contact details for a domain.
     * JSON-RPC: DisplayDomainContacts (tld, sld).
     */
    public function getContactDetails(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $rpcParams = array_merge($this->authParams(), [
                'tld' => $tld,
                'sld' => $sld,
            ]);

            $result = $this->rpcCall('DisplayDomainContacts', $rpcParams);
            if ($result['status'] !== 'success') {
                return $result;
            }

            // Referans düz contact objesi döner. AbstractRegistrar sözleşmesi:
            // contact detayları 'groups' anahtarıyla (Registrant/Admin/Tech/Billing).
            $c = is_array($result['data']) ? $result['data'] : [];
            $mapped = [
                'firstname' => $c['firstname'] ?? $c['first_name'] ?? '',
                'lastname' => $c['lastname'] ?? $c['last_name'] ?? '',
                'company' => $c['companyname'] ?? $c['company'] ?? '',
                'address1' => $c['address1'] ?? '',
                'address2' => $c['address2'] ?? '',
                'city' => $c['city'] ?? '',
                'state' => $c['state'] ?? '',
                'postcode' => $c['postcode'] ?? $c['zip'] ?? '',
                'country' => $c['country'] ?? $c['country_code'] ?? '',
                'phone' => $c['phonenumber'] ?? $c['phone'] ?? '',
                'email' => $c['email'] ?? '',
            ];

            $groups = [];
            foreach (['Registrant', 'Admin', 'Tech', 'Billing'] as $type) {
                $groups[$type] = $mapped;
            }

            return $this->successResponse(__('admin/modules.resellal_contacts_retrieved'), [
                'domain' => $sld . '.' . $tld,
                'groups' => $groups,
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Get contacts error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    // -------------------------------------------------------------------------
    //  Domain Details — referans synchInfo() → ListDomains (match)
    // -------------------------------------------------------------------------

    /**
     * Get domain details.
     * JSON-RPC: ListDomains — hesaptaki domain'i ada göre eşle (referans synchInfo).
     * Ayrıca ListNameservers ile NS'i tamamlar.
     */
    public function getDomainDetails(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $name = $sld . '.' . $tld;
            $match = $this->findAccountDomain($name);
            if ($match === null) {
                return $this->errorResponse(__('admin/modules.resellal_domain_not_found'));
            }

            $expiry = $match['expirydate'] ?? $match['expires'] ?? null;

            $nameservers = [];
            $nsResult = $this->getNameservers($params);
            if (($nsResult['status'] ?? 'error') === 'success') {
                $nameservers = $nsResult['data']['nameservers'] ?? [];
            }

            return $this->successResponse(__('admin/modules.resellal_domain_details_retrieved'), [
                'domain' => $name,
                'nameservers' => $nameservers,
                'auto_renew' => (bool) ($match['auto_renew'] ?? false),
                'expiry_date' => $expiry,
                'expires_at' => $expiry,
                'status' => $match['status'] ?? null,
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Get domain details error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    // -------------------------------------------------------------------------
    //  Availability — referans testConnection()/CheckDomain
    // -------------------------------------------------------------------------

    /**
     * Check domain availability.
     * JSON-RPC: CheckDomain (tld, sld). Referans tek domain sorgular.
     *
     * NOT (PRC-1060): DomainService kanonik zarfı ({status, data.available/
     * is_premium/premium_pricing}) parse eder — modül availability'yi data
     * altında doğru anahtarlarla döndürür.
     */
    public function checkDomainAvailability(array $params)
    {
        try {
            $this->validateConfig();

            ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
            if ($sld === '' || $tld === '') {
                return $this->errorResponse(__('admin/modules.resellal_domain_required'));
            }

            $rpcParams = array_merge($this->authParams(), [
                'tld' => $tld,
                'sld' => $sld,
            ]);

            $result = $this->rpcCall('CheckDomain', $rpcParams);
            if ($result['status'] !== 'success') {
                return $result;
            }

            // Resell.al CheckDomain başarılı yanıtı = domain müsait. Yanıt gövdesinde
            // açık `available` alanı varsa onu kullan; yoksa RPC error'ün olmaması
            // müsaitlik demektir (referans testConnection akışı).
            $data = is_array($result['data']) ? $result['data'] : [];
            $available = array_key_exists('available', $data)
                ? ($data['available'] === true || $data['available'] === 'true' || $data['available'] === 1)
                : true;

            return $this->successResponse(__('admin/modules.resellal_availability_checked'), [
                'domain' => $sld . '.' . $tld,
                'available' => $available,
                'is_premium' => false,
                'premium_pricing' => null,
            ]);
        } catch (\Exception $e) {
            Log::error('Resellal: Check availability error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }
    }

    // -------------------------------------------------------------------------
    //  Sync — referans synchInfo() → ListDomains
    // -------------------------------------------------------------------------

    /**
     * Sync domain data from the registrar (cron expiry/status).
     * getDomainDetails (ListDomains match) üzerinden.
     */
    public function syncDomain(array $params)
    {
        ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
        if ($sld === '' || $tld === '') {
            return $this->errorResponse(__('admin/modules.resellal_domain_required'));
        }

        $details = $this->getDomainDetails($params);
        if (($details['status'] ?? 'error') !== 'success') {
            return $details;
        }

        $d = $details['data'];

        return $this->successResponse(__('admin/modules.resellal_sync_success'), [
            'domain' => $sld . '.' . $tld,
            'status' => $d['status'] ?? null,
            'expiry_date' => $d['expiry_date'] ?? null,
            'expires_at' => $d['expiry_date'] ?? null,
            'auto_renew' => (bool) ($d['auto_renew'] ?? false),
            'synced_at' => now()->toISOString(),
        ]);
    }

    /**
     * Sync a pending transfer's status.
     * Ayrı transfer-poll endpoint'i referansta YOK; ListDomains'te domain
     * göründüyse transfer tamamlanmış (completed), görünmüyorsa henüz beklemede
     * (pending). Sahte-success/uydurma hata yok.
     */
    public function syncDomainTransfer(array $params)
    {
        ['sld' => $sld, 'tld' => $tld] = $this->splitDomain($params);
        if ($sld === '' || $tld === '') {
            return $this->errorResponse(__('admin/modules.resellal_domain_required'));
        }

        $name = $sld . '.' . $tld;

        try {
            $this->validateConfig();
            $match = $this->findAccountDomain($name);
        } catch (\Exception $e) {
            Log::error('Resellal: Sync transfer error', ['error' => $e->getMessage()]);

            return $this->errorResponse($e->getMessage());
        }

        if ($match === null) {
            // Hesapta yok → transfer henüz tamamlanmamış.
            return $this->successResponse(__('admin/modules.resellal_sync_transfer_success'), [
                'domain' => $name,
                'transfer_status' => 'pending',
                'synced_at' => now()->toISOString(),
            ]);
        }

        $status = strtolower((string) ($match['status'] ?? ''));
        $transferStatus = 'completed';
        if (in_array($status, ['failed', 'cancelled', 'canceled', 'rejected'], true)) {
            $transferStatus = 'failed';
        } elseif (in_array($status, ['pending', 'transfer', 'pendingtransfer'], true)) {
            $transferStatus = 'pending';
        }

        return $this->successResponse(__('admin/modules.resellal_sync_transfer_success'), [
            'domain' => $name,
            'transfer_status' => $transferStatus,
            'expiry_date' => $match['expirydate'] ?? $match['expires'] ?? null,
            'synced_at' => now()->toISOString(),
        ]);
    }

    // -------------------------------------------------------------------------
    //  Supported features
    // -------------------------------------------------------------------------

    /**
     * Referans `$commands` = Register/Transfer/Renew/ContactInfo + NS yardımcıları.
     * EPP code, lock, privacy, child-NS Resell.al API'sinde YOK.
     */
    public function getSupportedFeatures(): array
    {
        return ['nameservers', 'contacts'];
    }

    // -------------------------------------------------------------------------
    //  Unsupported operations — Resell.al JSON-RPC API'sinde karşılığı YOK.
    //  Uydurma endpoint yerine dürüst "desteklenmiyor" (sahte-success YASAK).
    // -------------------------------------------------------------------------

    /** EPP/auth code retrieval — Resell.al API'si sunmuyor. */
    public function getEppCode(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_epp_unsupported'));
    }

    /** Domain lock durumu — Resell.al API'si sunmuyor. */
    public function getDomainLock(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_lock_unsupported'));
    }

    /** Domain lock değiştirme — Resell.al API'si sunmuyor. */
    public function updateDomainLock(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_lock_unsupported'));
    }

    /** Domain pricing listesi — Resell.al API'si sunmuyor. */
    public function getDomainPricings(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_pricing_unsupported'));
    }

    /** Child nameserver (glue record) — Resell.al API'si sunmuyor. */
    public function getChildNameservers(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_child_ns_unsupported'));
    }

    public function addChildNameserver(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_child_ns_unsupported'));
    }

    public function updateChildNameserver(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_child_ns_unsupported'));
    }

    public function deleteChildNameserver(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_child_ns_unsupported'));
    }

    /** WHOIS privacy / ID protection toggle — Resell.al API'si sunmuyor. */
    public function updatePrivacySettings(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_privacy_unsupported'));
    }

    /** Domain suggestion/spin — Resell.al API'si sunmuyor. */
    public function checkDomainSuggestions(array $params)
    {
        return $this->errorResponse(__('admin/modules.resellal_suggestions_unsupported'));
    }

    // -------------------------------------------------------------------------
    //  Data Helpers
    // -------------------------------------------------------------------------

    /**
     * Kanonik registrant/contact grubunu (PRC-969 helper) referans düz alan
     * adlarına (firstname/lastname/companyname/.../phonenumber) map'ler.
     * Register/transfer/edit yönünde BOŞ gitmez.
     *
     * @return array<string,string>
     */
    protected function contactFields(array $params, string $group): array
    {
        $c = $this->contact($params, $group);

        return [
            'firstname' => $c['first_name'] ?? '',
            'lastname' => $c['last_name'] ?? '',
            'companyname' => $c['company'] ?? '',
            'address1' => $c['address1'] ?? '',
            'address2' => $c['address2'] ?? '',
            'city' => $c['city'] ?? '',
            'state' => $c['state'] ?? '',
            'postcode' => $c['postcode'] ?? '',
            'country' => $c['country_code'] ?? '',
            'email' => $c['email'] ?? '',
            'phonenumber' => $c['phone'] ?? '',
        ];
    }

    /**
     * modifyContact `groups` (module-authored alan adlı) → referans düz contact
     * alanları. Round-trip (#4): modülün KENDİ yazdığı alan adlarını korur;
     * registrant (veya ilk) grubu esas alınır (referans tek düz set kabul eder).
     * Bilinmeyen/ekstra alanlar da OLDUĞU GİBİ geçer (enjeksiyon yapılmaz).
     *
     * @param  array  $groups
     * @return array<string,mixed>
     */
    protected function flatFromModifyGroup(array $groups): array
    {
        // Registrant öncelikli; yoksa ilk grubu al.
        $chosen = null;
        foreach ($groups as $key => $fields) {
            if (! is_array($fields)) {
                continue;
            }
            if (strtolower((string) $key) === 'registrant') {
                $chosen = $fields;
                break;
            }
            if ($chosen === null) {
                $chosen = $fields;
            }
        }

        return is_array($chosen) ? $chosen : [];
    }

    /**
     * `nameservers` dizisini referans düz ns1..nsN alanlarına açar.
     *
     * @return array<string,string>
     */
    protected function nameserverFields(array $params, int $max): array
    {
        $nameservers = array_values(array_filter($params['nameservers'] ?? []));
        $out = [];
        for ($i = 1; $i <= $max; $i++) {
            $out['ns' . $i] = $nameservers[$i - 1] ?? '';
        }

        return $out;
    }

    /**
     * ListNameservers yanıtından NS listesi çıkar (referans esnek gövde).
     *
     * @return array<int,string>
     */
    protected function extractNameservers($data): array
    {
        if (! is_array($data)) {
            return [];
        }

        // Doğrudan indeksli liste.
        if (array_is_list($data)) {
            return array_values(array_filter(array_map('strval', $data)));
        }

        // `nameservers` alt-anahtarı.
        if (isset($data['nameservers']) && is_array($data['nameservers'])) {
            return array_values(array_filter(array_map('strval', $data['nameservers'])));
        }

        // ns1..nsN düz anahtarları.
        $out = [];
        for ($i = 1; $i <= 5; $i++) {
            $v = $data['ns' . $i] ?? null;
            if (! empty($v)) {
                $out[] = (string) $v;
            }
        }

        return $out;
    }

    /**
     * ListDomains ile hesaptaki domain'i ada göre eşle (referans synchInfo).
     *
     * @return array<string,mixed>|null  Eşleşen domain satırı, yoksa null
     */
    protected function findAccountDomain(string $name): ?array
    {
        $result = $this->rpcCall('ListDomains', $this->authParams());
        if ($result['status'] !== 'success') {
            return null;
        }

        $list = $result['data'];
        if (! is_array($list)) {
            return null;
        }

        foreach ($list as $domain) {
            if (! is_array($domain)) {
                continue;
            }
            $dn = $domain['domainname'] ?? $domain['domain'] ?? '';
            if (strcasecmp((string) $dn, $name) === 0) {
                return $domain;
            }
        }

        return null;
    }
}
