<?php

namespace App\Modules\Registrar\DonDominio;

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

class DonDominio extends AbstractRegistrar
{
    /**
     * DonDominio Simple API base URL
     */
    protected string $apiUrl = 'https://simple-api.dondominio.net';

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

    /**
     * Return the module configuration fields
     */
    public function getConfigFields(): array
    {
        return [
            'api_user' => [
                'type' => 'text',
                'label' => __('admin/modules.dondominio_field_api_user_label'),
                'required' => true,
                'description' => __('admin/modules.dondominio_field_api_user_description'),
                'placeholder' => 'your-api-user',
                'value' => $this->config['api_user'] ?? '',
            ],
            'api_password' => [
                'type' => 'password',
                'label' => __('admin/modules.dondominio_field_api_password_label'),
                'required' => true,
                'description' => __('admin/modules.dondominio_field_api_password_description'),
                'placeholder' => '********',
                'value' => $this->config['api_password'] ?? '',
            ],
        ];
    }

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

        if (empty($this->config['api_password'])) {
            throw new \Exception(__('admin/modules.dondominio_config_api_password_missing'));
        }

        return true;
    }

    // -------------------------------------------------------------------------
    //  API Helper
    // -------------------------------------------------------------------------

    /**
     * Make a POST request to the DonDominio Simple API.
     *
     * DonDominio Simple API envelope: { success: bool, errorCode: int (0=ok),
     * errorCodeMsg, messages[], responseData } — success is the BOOLEAN flag,
     * NOT a responseCode. (Ref: HostBill api.php:47 `if(!$json->success)`.)
     *
     * @param  string  $endpoint  API endpoint (e.g. /domain/create/)
     * @param  array  $params  Request parameters
     * @return array Standardised {status, message, data} response
     */
    protected function callApi($endpoint, $method = 'POST', $params = [])
    {
        $url = rtrim($this->apiUrl, '/').'/'.ltrim($endpoint, '/');

        // Inject authentication credentials + JSON output format
        $params['apiuser'] = $this->config['api_user'] ?? '';
        $params['apipasswd'] = $this->config['api_password'] ?? '';
        $params['output-format'] = 'json';

        Log::debug('DonDominio API request', [
            'endpoint' => $endpoint,
            'domain' => $params['domain'] ?? 'N/A',
        ]);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/x-www-form-urlencoded',
            'Accept: application/json',
        ]);

        $response = curl_exec($ch);
        $curlError = curl_error($ch);
        $curlErrno = curl_errno($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

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

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

        $decoded = json_decode($response, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            Log::error('DonDominio: Invalid JSON response', [
                'endpoint' => $endpoint,
                'http_code' => $httpCode,
            ]);

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

        $responseData = $decoded['responseData'] ?? [];

        // Success = boolean `success` flag (Simple API envelope), not a code.
        if (! empty($decoded['success'])) {
            return $this->successResponse(
                __('admin/modules.dondominio_action_success'),
                is_array($responseData) ? $responseData : []
            );
        }

        $errorCode = $decoded['errorCode'] ?? 'ERR';
        $errorCodeMsg = $decoded['errorCodeMsg'] ?? '';
        $messages = $decoded['messages'] ?? [];

        $parts = [];
        if ($errorCodeMsg !== '') {
            $parts[] = $errorCodeMsg;
        }
        if (is_array($messages)) {
            foreach ($messages as $m) {
                if (is_string($m) && $m !== '' && ! in_array($m, $parts, true)) {
                    $parts[] = $m;
                }
            }
        }

        $errorMessage = ! empty($parts) ? implode('; ', $parts) : __('admin/modules.dondominio_unknown_error');

        Log::error('DonDominio: API error', [
            'endpoint' => $endpoint,
            'error_code' => $errorCode,
            'messages' => $messages,
        ]);

        return $this->errorResponse("[{$errorCode}] {$errorMessage}");
    }

    // -------------------------------------------------------------------------
    //  Domain Registration
    // -------------------------------------------------------------------------

    /**
     * Register a domain
     */
    public function registerDomain(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $requestData = [
                'domain' => $domain,
                'period' => $params['period'] ?? 1,
                'premium' => ! empty($params['premium']) ? 'true' : 'false',
                'nameservers' => $this->buildNameserverString($params),
            ];

            // 4 canonical contact groups → owner/admin/tech/billing flat prefixed keys (PRC-969)
            foreach (['registrant', 'admin', 'tech', 'billing'] as $group) {
                $requestData += $this->prepareContact($params, $group);
            }

            // TLD-specific extra fields (.es IdentNumber, ownerDateOfBirth, ...) forwarded as-is
            $requestData = $this->mergeAdditionalFields($requestData, $params);

            if (! empty($params['owner_contact_id'])) {
                $requestData['ownerContactID'] = $params['owner_contact_id'];
            }

            $result = $this->callApi('/domain/create/', 'POST', $requestData);

            if ($result['status'] === 'success' || $result['status'] === 'pending') {
                Log::info('DonDominio: Domain registered', [
                    'domain' => $domain,
                    'period' => $params['period'] ?? 1,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Register domain error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Domain Transfer
    // -------------------------------------------------------------------------

    /**
     * Transfer a domain
     */
    public function transferDomain(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $nameservers = $this->buildNameserverString($params, 'keepns');

            $requestData = [
                'domain' => $domain,
                'authcode' => $params['epp_code'] ?? $params['authcode'] ?? '',
                'period' => $params['period'] ?? 1,
                'nameservers' => $nameservers,
            ];

            foreach (['registrant', 'admin', 'tech', 'billing'] as $group) {
                $requestData += $this->prepareContact($params, $group);
            }

            $requestData = $this->mergeAdditionalFields($requestData, $params);

            $result = $this->callApi('/domain/transfer/', 'POST', $requestData);

            if ($result['status'] === 'success' || $result['status'] === 'pending') {
                Log::info('DonDominio: Domain transfer initiated', ['domain' => $domain]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Transfer domain error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Domain Renewal
    // -------------------------------------------------------------------------

    /**
     * Renew a domain
     */
    public function renewDomain(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $requestData = [
                'domain' => $domain,
                'curExpDate' => $params['expiry_date'] ?? $params['curExpDate'] ?? '',
                'period' => $params['period'] ?? 1,
            ];

            $result = $this->callApi('/domain/renew/', 'POST', $requestData);

            if ($result['status'] === 'success' || $result['status'] === 'pending') {
                Log::info('DonDominio: Domain renewed', [
                    'domain' => $domain,
                    'period' => $params['period'] ?? 1,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Renew domain error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Nameservers
    // -------------------------------------------------------------------------

    /**
     * Get nameservers for a domain
     */
    public function getNameservers(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getinfo/', 'POST', [
                'domain' => $domain,
                'infoType' => 'nameservers',
            ]);

            if ($result['status'] === 'success') {
                $nameservers = [];
                // responseData.nameservers[] each an object with `.name` (Ref: class.dondominio.php:194)
                $nsData = $result['data']['nameservers'] ?? [];

                if (is_array($nsData)) {
                    foreach ($nsData as $value) {
                        if (is_array($value) && isset($value['name'])) {
                            $nameservers[] = $value['name'];
                        } elseif (is_string($value) && $value !== '') {
                            $nameservers[] = $value;
                        }
                    }
                }

                return $this->successResponse(__('admin/modules.dondominio_nameservers_retrieved'), [
                    'domain' => $domain,
                    'nameservers' => $nameservers,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Get nameservers error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Set nameservers for a domain
     */
    public function setNameservers(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $nameservers = $this->buildNameserverString($params);

            $result = $this->callApi('/domain/updatenameservers/', 'POST', [
                'domain' => $domain,
                'nameservers' => $nameservers,
            ]);

            if ($result['status'] === 'success') {
                Log::info('DonDominio: Nameservers updated', ['domain' => $domain]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Set nameservers error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Child Nameservers (Glue Records)
    // -------------------------------------------------------------------------

    /**
     * Get child nameservers (glue records) for a domain.
     * getinfo infoType=gluerecords → responseData.gluerecords[] {name, ipv4, ipv6}.
     * (Ref: class.dondominio.php:248-261)
     */
    public function getChildNameservers(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getinfo/', 'POST', [
                'domain' => $domain,
                'infoType' => 'gluerecords',
            ]);

            if ($result['status'] === 'success') {
                $records = [];
                $glue = $result['data']['gluerecords'] ?? [];

                if (is_array($glue)) {
                    foreach ($glue as $g) {
                        if (! is_array($g) || empty($g['name'])) {
                            continue;
                        }
                        // Strip ".domain" suffix from FQDN to obtain the host label
                        $host = str_replace('.'.$domain, '', (string) $g['name']);
                        $records[] = [
                            'host' => $host,
                            'ip' => $g['ipv4'] ?? $g['ipv6'] ?? '',
                        ];
                    }
                }

                return $this->successResponse(__('admin/modules.dondominio_child_ns_retrieved'), [
                    'domain' => $domain,
                    'nameservers' => $records,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Get child nameservers error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Create a child nameserver (glue record).
     * domain/gluerecordcreate: domain, name=FQDN, ipv4|ipv6 (colon-detect).
     * (Ref: class.dondominio.php:213-224)
     */
    public function addChildNameserver(array $params)
    {
        $domain = $params['domain'] ?? '';
        $host = $params['hostname'] ?? $params['host'] ?? $params['nameserver'] ?? '';
        $ip = $params['ip'] ?? $params['ipaddress'] ?? '';

        if (empty($domain) || empty($host) || empty($ip)) {
            return $this->errorResponse(__('admin/modules.dondominio_child_ns_missing_param'));
        }

        try {
            $this->validateConfig();

            $requestData = [
                'domain' => $domain,
                'name' => $this->childHostFqdn($host, $domain),
                $this->ipType($ip) => $ip,
            ];

            $result = $this->callApi('/domain/gluerecordcreate/', 'POST', $requestData);

            if ($result['status'] === 'success') {
                Log::info('DonDominio: Child nameserver created', ['domain' => $domain]);

                return $this->successResponse(__('admin/modules.dondominio_child_ns_created'), [
                    'domain' => $domain,
                    'host' => $host,
                    'ip' => $ip,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Add child nameserver error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Update a child nameserver (glue record) with a new IP.
     * domain/gluerecordupdate: domain, name=FQDN, ipv4|ipv6 (new IP).
     * (Ref: class.dondominio.php:225-236)
     */
    public function updateChildNameserver(array $params)
    {
        $domain = $params['domain'] ?? '';
        $host = $params['hostname'] ?? $params['host'] ?? $params['nameserver'] ?? '';
        $newIp = $params['ip'] ?? $params['newip'] ?? $params['new_ip'] ?? '';

        if (empty($domain) || empty($host) || empty($newIp)) {
            return $this->errorResponse(__('admin/modules.dondominio_child_ns_missing_param'));
        }

        try {
            $this->validateConfig();

            $requestData = [
                'domain' => $domain,
                'name' => $this->childHostFqdn($host, $domain),
                $this->ipType($newIp) => $newIp,
            ];

            $result = $this->callApi('/domain/gluerecordupdate/', 'POST', $requestData);

            if ($result['status'] === 'success') {
                Log::info('DonDominio: Child nameserver updated', ['domain' => $domain]);

                return $this->successResponse(__('admin/modules.dondominio_child_ns_updated'), [
                    'domain' => $domain,
                    'host' => $host,
                    'ip' => $newIp,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Update child nameserver error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Delete a child nameserver (glue record).
     * domain/gluerecorddelete: domain, name=FQDN (no IP).
     * (Ref: class.dondominio.php:237-247)
     */
    public function deleteChildNameserver(array $params)
    {
        $domain = $params['domain'] ?? '';
        $host = $params['hostname'] ?? $params['host'] ?? $params['nameserver'] ?? '';

        if (empty($domain) || empty($host)) {
            return $this->errorResponse(__('admin/modules.dondominio_child_ns_missing_param'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/gluerecorddelete/', 'POST', [
                'domain' => $domain,
                'name' => $this->childHostFqdn($host, $domain),
            ]);

            if ($result['status'] === 'success') {
                Log::info('DonDominio: Child nameserver deleted', ['domain' => $domain]);

                return $this->successResponse(__('admin/modules.dondominio_child_ns_deleted'), [
                    'domain' => $domain,
                    'host' => $host,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Delete child nameserver error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Contact Details
    // -------------------------------------------------------------------------

    /**
     * Get contact details for a domain, mapped into canonical groups.
     * getinfo infoType=contact → contactOwner/contactAdmin/contactTech/contactBilling.
     * (Ref: class.dondominio.php:262-277)
     */
    public function getContactDetails(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getinfo/', 'POST', [
                'domain' => $domain,
                'infoType' => 'contact',
            ]);

            if ($result['status'] === 'success') {
                $data = $result['data'] ?? [];
                $groups = [];

                $map = [
                    'Registrant' => 'contactOwner',
                    'Admin' => 'contactAdmin',
                    'Tech' => 'contactTech',
                    'Billing' => 'contactBilling',
                ];

                foreach ($map as $group => $key) {
                    $c = $data[$key] ?? [];
                    if (! is_array($c) || empty($c)) {
                        continue;
                    }
                    $groups[$group] = [
                        'firstname' => $c['firstName'] ?? '',
                        'lastname' => $c['lastName'] ?? '',
                        'company' => $c['orgName'] ?? '',
                        'address1' => $c['address'] ?? '',
                        'address2' => '',
                        'city' => $c['city'] ?? '',
                        'state' => $c['state'] ?? '',
                        'postcode' => $c['postalCode'] ?? '',
                        'country' => $c['country'] ?? '',
                        'phone' => $c['phone'] ?? '',
                        'email' => $c['email'] ?? '',
                    ];
                }

                return [
                    'status' => 'success',
                    'message' => __('admin/modules.dondominio_contacts_retrieved'),
                    'groups' => $groups,
                ];
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Get contact details error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Set contact details for a domain.
     * Reads canonical `groups` (Registrant/Admin/Tech/Billing) and emits the flat
     * owner/admin/tech/billing prefixed API shape (Ref: class.dondominio.php:278-288).
     */
    public function setContactDetails(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $requestData = ['domain' => $domain];

            $groups = $params['groups'] ?? [];
            $groupMap = [
                'Registrant' => 'registrant',
                'Admin' => 'admin',
                'Tech' => 'tech',
                'Billing' => 'billing',
            ];

            foreach ($groupMap as $uc => $group) {
                $cdata = $groups[$uc] ?? $groups[$group] ?? null;
                if (! is_array($cdata) || empty($cdata)) {
                    continue;
                }
                $requestData += $this->prepareContactFromArray($cdata, $group);
            }

            $result = $this->callApi('/domain/updatecontacts/', 'POST', $requestData);

            if ($result['status'] === 'success') {
                Log::info('DonDominio: Contacts updated', ['domain' => $domain]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Set contact details error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Domain Details & Sync
    // -------------------------------------------------------------------------

    /**
     * Get domain details (status info), mapped to canonical fields.
     * (Ref: class.dondominio.php synchInfo — status/tsExpir/whoisPrivacy/transferBlock)
     */
    public function getDomainDetails(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getinfo/', 'POST', [
                'domain' => $domain,
                'infoType' => 'status',
            ]);

            if ($result['status'] === 'success') {
                $data = $result['data'] ?? [];

                return $this->successResponse(__('admin/modules.dondominio_details_retrieved'), [
                    'domain' => $domain,
                    'status' => $data['status'] ?? '',
                    'expires_at' => $data['tsExpir'] ?? '',
                    'locked' => ! empty($data['transferBlock']),
                    'id_protection' => ! empty($data['whoisPrivacy']),
                    'renewalMode' => $data['renewalMode'] ?? null,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Get domain details error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Sync domain status/expiry from the registrar (cron).
     * getinfo infoType=status → status/tsExpir/whoisPrivacy/transferBlock.
     * (Ref: class.dondominio.php synchInfo:97-122)
     */
    public function syncDomain(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getinfo/', 'POST', [
                'domain' => $domain,
                'infoType' => 'status',
            ]);

            if ($result['status'] !== 'success') {
                return $result;
            }

            $data = $result['data'] ?? [];

            $status = ($data['status'] ?? '') === 'active' ? 'Active' : ($data['status'] ?? '');
            $expiryDate = $data['tsExpir'] ?? null;

            if ($expiryDate) {
                $ts = strtotime($expiryDate);
                if ($ts !== false && $ts < time()) {
                    $status = 'Expired';
                }
            }

            return $this->successResponse(__('admin/modules.dondominio_sync_success'), [
                'domain' => $domain,
                'status' => $status,
                'expiry_date' => $expiryDate,
                'id_protection' => ! empty($data['whoisPrivacy']),
                'locked' => ! empty($data['transferBlock']),
                'synced_at' => now()->toISOString(),
            ]);
        } catch (\Exception $e) {
            Log::error('DonDominio: Sync domain error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Poll a pending transfer. Once the domain resolves to active status the
     * transfer is complete; otherwise it is still pending.
     * (Post-order polling uses getinfo status, like synchInfo.)
     */
    public function syncDomainTransfer(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getinfo/', 'POST', [
                'domain' => $domain,
                'infoType' => 'status',
            ]);

            if ($result['status'] !== 'success') {
                // Domain not yet in the account → transfer still pending
                return $this->successResponse(__('admin/modules.dondominio_transfer_pending'), [
                    'domain' => $domain,
                    'status' => 'pending',
                ]);
            }

            $data = $result['data'] ?? [];
            $active = ($data['status'] ?? '') === 'active';

            return $this->successResponse(
                $active
                    ? __('admin/modules.dondominio_transfer_completed')
                    : __('admin/modules.dondominio_transfer_pending'),
                [
                    'domain' => $domain,
                    'status' => $active ? 'completed' : 'pending',
                    'expiry_date' => $data['tsExpir'] ?? null,
                ]
            );
        } catch (\Exception $e) {
            Log::error('DonDominio: Sync domain transfer error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Domain Lock (Transfer Block)
    // -------------------------------------------------------------------------

    /**
     * Get domain lock status
     */
    public function getDomainLock(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getinfo/', 'POST', [
                'domain' => $domain,
                'infoType' => 'status',
            ]);

            if ($result['status'] === 'success') {
                $data = $result['data'] ?? [];
                $locked = ! empty($data['transferBlock']);

                return $this->successResponse(__('admin/modules.dondominio_lock_retrieved'), [
                    'domain' => $domain,
                    'locked' => $locked,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Get domain lock error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Update domain lock (transfer block).
     * domain/update updateType=transferBlock (Ref: class.dondominio.php:146-160).
     */
    public function updateDomainLock(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $lock = ! empty($params['lock']) || ! empty($params['locked']) || ! empty($params['lock_status']);

            $result = $this->callApi('/domain/update/', 'POST', [
                'domain' => $domain,
                'updateType' => 'transferBlock',
                'transferBlock' => $lock ? 'true' : 'false',
            ]);

            if ($result['status'] === 'success') {
                Log::info('DonDominio: Domain lock updated', [
                    'domain' => $domain,
                    'locked' => $lock,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Update domain lock error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Privacy (WHOIS Protection)
    // -------------------------------------------------------------------------

    /**
     * Update WHOIS privacy protection.
     * domain/update updateType=whoisPrivacy (Ref: class.dondominio.php:174-188).
     */
    public function updatePrivacySettings(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $enable = ! empty($params['id_protection']) || ! empty($params['privacy']) || ! empty($params['enable']);

            $result = $this->callApi('/domain/update/', 'POST', [
                'domain' => $domain,
                'updateType' => 'whoisPrivacy',
                'whoisPrivacy' => $enable ? 'true' : 'false',
            ]);

            if ($result['status'] === 'success') {
                Log::info('DonDominio: Privacy updated', [
                    'domain' => $domain,
                    'privacy' => $enable,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Update privacy error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  EPP Code (Auth Code)
    // -------------------------------------------------------------------------

    /**
     * Get EPP/Auth code for a domain.
     * getinfo infoType=authcode → responseData.authcode (Ref: class.dondominio.php:123-132).
     */
    public function getEppCode(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getinfo/', 'POST', [
                'domain' => $domain,
                'infoType' => 'authcode',
            ]);

            if ($result['status'] === 'success') {
                Log::info('DonDominio: EPP code retrieved', ['domain' => $domain]);

                return $this->successResponse(__('admin/modules.dondominio_epp_retrieved'), [
                    'domain' => $domain,
                    'epp_code' => $result['data']['authcode'] ?? '',
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Get EPP code error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Domain Availability & Suggestions
    // -------------------------------------------------------------------------

    /**
     * Check domain availability
     */
    public function checkDomainAvailability(array $params)
    {
        $domain = $params['domain'] ?? '';
        if (empty($domain)) {
            return $this->errorResponse(__('admin/modules.dondominio_domain_required'));
        }

        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/check/', 'POST', [
                'domain' => $domain,
            ]);

            if ($result['status'] === 'success') {
                // /domain/check/ returns responseData.domains[] — an array of
                // domain objects {name, punycode, tld, available, premium, price,
                // currency}, NOT flat availability keys. Ref: dondominio.dev
                // /domain/check/ responseData.domains[].
                $data = $result['data'] ?? [];
                $d = $data['domains'][0] ?? $data;

                return $this->successResponse(__('admin/modules.dondominio_availability_checked'), [
                    'domain' => $domain,
                    'available' => ! empty($d['available']),
                    'premium' => ! empty($d['premium']),
                    'price' => $d['price'] ?? null,
                    'currency' => $d['currency'] ?? null,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Check domain availability error', [
                'domain' => $domain,
                'error' => $e->getMessage(),
            ]);

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

    /**
     * Suggest available domains based on a search word.
     * tool/domainsuggests → responseData with variations + availability.
     */
    public function checkDomainSuggestions(array $params)
    {
        $query = $params['query'] ?? $params['keyword'] ?? $params['domain'] ?? '';
        if (empty($query)) {
            return $this->errorResponse(__('admin/modules.dondominio_suggestions_query_required'));
        }

        try {
            $this->validateConfig();

            $requestData = ['query' => $query];
            if (! empty($params['tlds'])) {
                $requestData['tlds'] = is_array($params['tlds']) ? implode(',', $params['tlds']) : $params['tlds'];
            }
            if (! empty($params['language'])) {
                $requestData['language'] = $params['language'];
            }

            $result = $this->callApi('/tool/domainsuggests/', 'POST', $requestData);

            if ($result['status'] === 'success') {
                // /tool/domainsuggests/ returns responseData = {query, suggests},
                // where `suggests` is keyed by WORD with a nested {tld: bool}
                // availability map, e.g.
                // {"query":"coches","suggests":{"cochesonline":{"es":false,"com":true}}}
                // — NO domain/price fields. Build fqdn = word.tld,
                // available = bool. Ref: dondominio.dev /tool/domainsuggests/.
                $data = $result['data'] ?? [];
                $suggests = $data['suggests'] ?? [];
                $suggestions = [];

                foreach ($suggests as $word => $tldMap) {
                    if (! is_array($tldMap) || ! is_string($word) || $word === '') {
                        continue;
                    }
                    foreach ($tldMap as $tld => $available) {
                        $suggestions[] = [
                            'domain' => $word . '.' . ltrim((string) $tld, '.'),
                            'available' => (bool) $available,
                            'price' => null,
                            'currency' => null,
                        ];
                    }
                }

                return $this->successResponse(__('admin/modules.dondominio_suggestions_retrieved'), [
                    'query' => $query,
                    'suggestions' => $suggestions,
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Check domain suggestions error', [
                'query' => $query,
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  Domain Pricings
    // -------------------------------------------------------------------------

    /**
     * Get domain pricing information
     */
    public function getDomainPricings(array $params)
    {
        try {
            $this->validateConfig();

            $result = $this->callApi('/domain/getprices/', 'POST', $params);

            if ($result['status'] === 'success') {
                return $this->successResponse(__('admin/modules.dondominio_pricings_retrieved'), [
                    'pricings' => $result['data'] ?? [],
                ]);
            }

            return $result;
        } catch (\Exception $e) {
            Log::error('DonDominio: Get domain pricings error', [
                'error' => $e->getMessage(),
            ]);

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

    // -------------------------------------------------------------------------
    //  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,
        ];
    }

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

    // -------------------------------------------------------------------------
    //  Internal Helpers
    // -------------------------------------------------------------------------

    /**
     * Build a comma-separated nameserver string from params.
     * Defaults to a literal ('parking'/'keepns') when none present — the API
     * requires min 2 NS and rejects empty (Ref: class.dondominio.php _nameservers:347-360).
     */
    protected function buildNameserverString(array $params, string $default = 'parking'): string
    {
        $nameservers = $params['nameservers'] ?? [];

        if (empty($nameservers)) {
            for ($i = 1; $i <= 5; $i++) {
                $ns = $params["ns{$i}"] ?? $params["nameserver{$i}"] ?? '';
                if (! empty($ns)) {
                    $nameservers[] = $ns;
                }
            }
        }

        if (empty($nameservers)) {
            return $default;
        }

        $str = is_array($nameservers) ? implode(',', array_filter($nameservers)) : (string) $nameservers;

        return $str !== '' ? $str : $default;
    }

    /**
     * Build the flat {owner|admin|tech|billing}Contact* payload for a group,
     * sourcing canonical contact data from the PRC-969 contact() helper.
     * registrant → prefix `owner` (Ref: class.dondominio.php prepareContact:289-317).
     */
    protected function prepareContact(array $params, string $group): array
    {
        $c = $this->contact($params, $group);

        return $this->prepareContactFromArray([
            'firstname' => $c['first_name'] ?? '',
            'lastname' => $c['last_name'] ?? '',
            'company' => $c['company'] ?? '',
            'email' => $c['email'] ?? '',
            'phone' => $c['phone'] ?? '',
            'address1' => $c['address1'] ?? '',
            'address2' => $c['address2'] ?? '',
            'city' => $c['city'] ?? '',
            'state' => $c['state'] ?? '',
            'postcode' => $c['postcode'] ?? '',
            'country' => $c['country_code'] ?? '',
        ], $group);
    }

    /**
     * Emit the flat prefixed contact keys for a single group from a canonical
     * field array (firstname/lastname/company/email/phone/address1/address2/
     * city/state/postcode/country). registrant → prefix `owner`.
     */
    protected function prepareContactFromArray(array $cdata, string $group): array
    {
        $address = trim(implode(' ', array_filter([
            $cdata['address1'] ?? '',
            $cdata['address2'] ?? '',
        ])));

        $company = $cdata['company'] ?? $cdata['companyname'] ?? '';
        $type = empty($company) ? 'individual' : 'organization';

        $contact = [
            'Type' => $type,
            'FirstName' => $cdata['firstname'] ?? '',
            'LastName' => $cdata['lastname'] ?? '',
            'IdentNumber' => $cdata['identnumber'] ?? '',
            'Email' => $cdata['email'] ?? '',
            'Phone' => $this->formatPhone($cdata['phone'] ?? ''),
            'Fax' => '+00.000000000',
            'Address' => $address,
            'PostalCode' => $cdata['postcode'] ?? $cdata['postal_code'] ?? '',
            'City' => $cdata['city'] ?? '',
            'State' => $cdata['state'] ?? '',
            'Country' => $cdata['country'] ?? $cdata['country_code'] ?? '',
        ];

        if ($type === 'organization') {
            $contact['OrgName'] = $company;
            $contact['OrgType'] = '';
        }

        $prefix = $group === 'registrant' ? 'owner' : $group;

        $out = [];
        foreach ($contact as $k => $v) {
            $out[$prefix.'Contact'.$k] = $v;
        }

        return $out;
    }

    /**
     * Forward TLD-specific extra fields (.es IdentNumber, ownerDateOfBirth, ...)
     * from the builder-emitted $params['additional_fields'] into the payload.
     */
    protected function mergeAdditionalFields(array $requestData, array $params): array
    {
        $extra = $params['additional_fields'] ?? [];
        if (! is_array($extra)) {
            return $requestData;
        }

        foreach ($extra as $key => $value) {
            if ($value === '' || $value === null) {
                continue;
            }
            // 'ContactIdentNumber' → registrant IdentNumber shortcut
            if ($key === 'ContactIdentNumber') {
                $requestData['ownerContactIdentNumber'] = $value;

                continue;
            }
            if (! array_key_exists($key, $requestData)) {
                $requestData[$key] = $value;
            }
        }

        return $requestData;
    }

    /**
     * Format a phone number to the DonDominio "+CC.NUMBER" shape.
     */
    protected function formatPhone(string $phone): string
    {
        $phone = trim($phone);
        if ($phone === '') {
            return '+00.000000000';
        }
        if (str_contains($phone, '.')) {
            return $phone;
        }

        $phone = str_replace(' ', '', $phone);
        if (str_starts_with($phone, '+') && strlen($phone) > 3) {
            // "+34600..." → "+34.600..."
            return substr($phone, 0, 3).'.'.substr($phone, 3);
        }

        return $phone;
    }

    /**
     * Build the fully-qualified glue-record hostname (host.domain), avoiding
     * double-suffix if the caller already passed an FQDN.
     */
    protected function childHostFqdn(string $host, string $domain): string
    {
        $host = rtrim($host, '.');
        if (str_ends_with(strtolower($host), '.'.strtolower($domain))) {
            return $host;
        }

        return $host.'.'.$domain;
    }

    /**
     * Determine the IP field name (ipv4/ipv6) by colon detection.
     */
    protected function ipType(string $ip): string
    {
        return str_contains($ip, ':') ? 'ipv6' : 'ipv4';
    }
}
