<?php

namespace App\Modules\Product\MaestroPanel;

use App\Core\Product\AbstractProduct;
use App\Core\Product\Events\AccountCreated;

class MaestroPanel extends AbstractProduct
{
    /**
     * MaestroPanel REST API port
     */
    protected int $apiPort = 9715;

    /**
     * MaestroPanel REST API version path
     */
    protected string $apiVersion = 'Api/v1';

    /**
     * MaestroPanel module requires a server
     */
    public function requiresServer(): bool
    {
        return true;
    }

    // =========================================================================
    // ACCOUNT OPERATIONS
    // =========================================================================

    /**
     * Create a new MaestroPanel hosting account (domain).
     *
     * POST /Api/v1/Domain/Create
     *
     * @param  array  $params  Required: domain, plan, username, password
     * @return array Operation result
     */
    public function createAccount(array $params)
    {
        // domain zorunlu; username/password/plan yoksa üret/fallback (PRC-1015 param-gate).
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_param_missing', ['param' => 'domain']),
            ];
        }

        // plan: flat $params['plan'] → module-config plan/package → 'default'
        $plan = $params['plan']
            ?? $this->moduleConfig($params, 'plan', $this->moduleConfig($params, 'package', ''));
        if (empty($plan)) {
            $plan = 'default';
        }

        // username: flat → domain'den türet (WiseCP UsernameGenerator davranışı)
        $username = $params['username'] ?? '';
        if (empty($username)) {
            $username = $this->generateUsername((string) $params['domain']);
        }

        // password: flat → rastgele güçlü parola üret (min 8, 2+ non-alphanumeric — resmî API min gereksinimi)
        $password = $params['password'] ?? '';
        if (empty($password)) {
            $password = $this->generatePassword();
        }

        // Contact alanları: builder flat alias'ları (first_name/last_name/email).
        $firstName = $this->contactField($params, ['firstname', 'first_name']);
        $lastName = $this->contactField($params, ['lastname', 'last_name']);
        $email = $this->contactField($params, ['email', 'client_email']);

        // Resmî Domain/Create packet (WHMCS + resmî PHP sample ile birebir):
        // name/planAlias/username/password/firstname/lastname/email/activedomainuser=true
        $postData = [
            'name' => $params['domain'],
            'planAlias' => $plan,
            'username' => $username,
            'password' => $password,
            'firstname' => $firstName,
            'lastname' => $lastName,
            'email' => $email,
            'activedomainuser' => 'true',
        ];

        $response = $this->callApi('/Domain/Create', 'POST', $postData, $params);

        if (isset($response['Code']) && $response['Code'] === 0) {
            $result = [
                'status' => 'success',
                'message' => __('admin/modules.maestropanel_account_created_success'),
                'data' => $response,
            ];

            AccountCreated::dispatch($params, $result);

            return $result;
        }

        $result = [
            'status' => 'error',
            'message' => $response['Message'] ?? __('admin/modules.maestropanel_account_create_failed'),
            'data' => $response,
        ];

        AccountCreated::dispatch($params, $result);

        return $result;
    }

    /**
     * Suspend (stop) a MaestroPanel hosting account.
     *
     * POST /Api/v1/Domain/Stop
     *
     * @param  array  $params  Required: domain
     * @return array Operation result
     */
    public function suspendAccount(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_domain_required'),
            ];
        }

        $response = $this->callApi('/Domain/Stop', 'POST', [
            'name' => $params['domain'],
        ], $params);

        if (isset($response['Code']) && $response['Code'] === 0) {
            return [
                'status' => 'success',
                'message' => __('admin/modules.maestropanel_account_suspended_success'),
            ];
        }

        return [
            'status' => 'error',
            'message' => $response['Message'] ?? __('admin/modules.maestropanel_account_suspend_failed'),
            'data' => $response,
        ];
    }

    /**
     * Unsuspend (start) a MaestroPanel hosting account.
     *
     * POST /Api/v1/Domain/Start
     *
     * @param  array  $params  Required: domain
     * @return array Operation result
     */
    public function unsuspendAccount(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_domain_required'),
            ];
        }

        $response = $this->callApi('/Domain/Start', 'POST', [
            'name' => $params['domain'],
        ], $params);

        if (isset($response['Code']) && $response['Code'] === 0) {
            return [
                'status' => 'success',
                'message' => __('admin/modules.maestropanel_account_unsuspended_success'),
            ];
        }

        return [
            'status' => 'error',
            'message' => $response['Message'] ?? __('admin/modules.maestropanel_account_unsuspend_failed'),
            'data' => $response,
        ];
    }

    /**
     * Terminate (delete) a MaestroPanel hosting account.
     *
     * DELETE /Api/v1/Domain/Delete
     *
     * @param  array  $params  Required: domain
     * @return array Operation result
     */
    public function terminateAccount(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_domain_required'),
            ];
        }

        $response = $this->callApi('/Domain/Delete', 'DELETE', [
            'name' => $params['domain'],
        ], $params);

        if (isset($response['Code']) && $response['Code'] === 0) {
            return [
                'status' => 'success',
                'message' => __('admin/modules.maestropanel_account_deleted_success'),
            ];
        }

        return [
            'status' => 'error',
            'message' => $response['Message'] ?? __('admin/modules.maestropanel_account_delete_failed'),
            'data' => $response,
        ];
    }

    /**
     * Change account password on MaestroPanel.
     *
     * POST /Api/v1/Domain/Password  (resmî endpoint; field: newpassword)
     *
     * @param  array  $params  Required: domain, password
     * @return array Operation result
     */
    public function changeAccountPassword(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_domain_required'),
            ];
        }

        if (! isset($params['password']) || empty($params['password'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_password_required'),
            ];
        }

        $response = $this->callApi('/Domain/Password', 'POST', [
            'name' => $params['domain'],
            'newpassword' => $params['password'],
        ], $params);

        if (isset($response['Code']) && $response['Code'] === 0) {
            return [
                'status' => 'success',
                'message' => __('admin/modules.maestropanel_password_changed_success'),
            ];
        }

        return [
            'status' => 'error',
            'message' => $response['Message'] ?? __('admin/modules.maestropanel_password_change_failed'),
            'data' => $response,
        ];
    }

    // =========================================================================
    // PACKAGE OPERATIONS
    // =========================================================================

    /**
     * Change account hosting plan on MaestroPanel.
     *
     * POST /Api/v1/Domain/SetDomainPlan  (action=protect ile mevcut kaynak
     * limitlerini korur). Referans: WiseCP MaestroPanel modülü.
     *
     * @param  array  $params  Required: domain, plan
     * @return array Operation result
     */
    public function changeAccountPackage(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_domain_required'),
            ];
        }

        // package/plan flat: builder module-config'ten emit eder; yoksa fallback.
        $plan = $params['plan'] ?? $this->moduleConfig($params, 'plan', $this->moduleConfig($params, 'package', ''));

        if (empty($plan)) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_plan_required'),
            ];
        }

        $response = $this->callApi('/Domain/SetDomainPlan', 'POST', [
            'name' => $params['domain'],
            'planAlias' => $plan,
            'action' => 'protect',
        ], $params);

        if (isset($response['Code']) && $response['Code'] === 0) {
            return [
                'status' => 'success',
                'message' => __('admin/modules.maestropanel_package_changed_success'),
            ];
        }

        return [
            'status' => 'error',
            'message' => $response['Message'] ?? __('admin/modules.maestropanel_package_change_failed'),
            'data' => $response,
        ];
    }

    // =========================================================================
    // CONNECTION TEST
    // =========================================================================

    /**
     * Test connection to MaestroPanel server.
     *
     * GET /Api/v1/Domain/GetList
     *
     * @param  array  $params  Test parameters
     * @return array Test result
     */
    public function testConnection(array $params = [])
    {
        $response = $this->callApi('/Domain/GetList', 'GET', [], $params);

        if (isset($response['Code']) && $response['Code'] === 0) {
            return [
                'status' => 'success',
                'message' => __('admin/modules.maestropanel_connection_test_success'),
                'data' => $response,
            ];
        }

        return [
            'status' => 'error',
            'message' => __('admin/modules.maestropanel_connection_test_failed'),
            'data' => $response,
        ];
    }

    // =========================================================================
    // FIELD DEFINITIONS
    // =========================================================================

    /**
     * Admin panel field definitions for module configuration.
     *
     * @return array Admin fields
     */
    public function adminFields()
    {
        return [
            'hostname' => [
                'name' => __('admin/modules.maestropanel_field_hostname'),
                'type' => 'text',
                'description' => __('admin/modules.maestropanel_field_hostname_description'),
                'required' => true,
            ],
            'port' => [
                'name' => __('admin/modules.maestropanel_field_port'),
                'type' => 'text',
                'description' => __('admin/modules.maestropanel_field_port_description'),
                'default' => '9715',
                'required' => false,
            ],
            'api_key' => [
                'name' => __('admin/modules.maestropanel_field_api_key'),
                'type' => 'password',
                'description' => __('admin/modules.maestropanel_field_api_key_description'),
                'required' => true,
            ],
            'use_ssl' => [
                'name' => __('admin/modules.maestropanel_field_use_ssl'),
                'type' => 'checkbox',
                'description' => __('admin/modules.maestropanel_field_use_ssl_description'),
                'default' => true,
            ],
        ];
    }

    /**
     * Client-side field definitions for service provisioning.
     *
     * @return array Client fields
     */
    public function clientFields()
    {
        return [
            'domain' => [
                'name' => __('admin/modules.maestropanel_field_domain'),
                'type' => 'text',
                'description' => __('admin/modules.maestropanel_field_domain_description'),
                'required' => true,
            ],
            'username' => [
                'name' => __('admin/modules.maestropanel_field_username'),
                'type' => 'text',
                'description' => __('admin/modules.maestropanel_field_username_description'),
                'required' => true,
            ],
            'password' => [
                'name' => __('admin/modules.maestropanel_field_password'),
                'type' => 'password',
                'description' => __('admin/modules.maestropanel_field_password_description'),
                'required' => true,
            ],
        ];
    }

    /**
     * Server-level field definitions.
     *
     * @return array Server fields
     */
    public function serverFields()
    {
        return [
            'api_key' => [
                'name' => __('admin/modules.maestropanel_field_api_key'),
                'type' => 'password',
                'description' => __('admin/modules.maestropanel_field_api_key_description'),
                'required' => true,
            ],
        ];
    }

    // =========================================================================
    // ADMIN BUTTONS & ACTIONS
    // =========================================================================

    /**
     * Admin panel custom buttons for this module.
     *
     * @return array Admin buttons
     */
    public function getAdminButtons(): array
    {
        return [
            [
                'action' => 'list_plans',
                'label' => __('admin/modules.maestropanel_action_list_plans'),
                'icon' => 'fas fa-list',
                'class' => 'btn-outline-info',
            ],
            [
                'action' => 'domain_details',
                'label' => __('admin/modules.maestropanel_action_domain_details'),
                'icon' => 'fas fa-info-circle',
                'class' => 'btn-outline-primary',
            ],
        ];
    }

    /**
     * Handle admin custom action.
     *
     * @param  string  $action  Action name (list_plans, domain_details)
     * @param  array  $params  Parameters
     * @return array Operation result
     */
    public function adminCustomAction(string $action, array $params): array
    {
        switch ($action) {
            case 'list_plans':
                $response = $this->callApi('/Plan/GetList', 'GET', [], $params);

                if (! isset($response['Code']) || $response['Code'] !== 0) {
                    return [
                        'status' => 'error',
                        'message' => $response['Message'] ?? __('admin/modules.maestropanel_list_plans_failed'),
                    ];
                }

                $plans = [];
                if (isset($response['Details']) && is_array($response['Details'])) {
                    foreach ($response['Details'] as $plan) {
                        $plans[] = [
                            'name' => $plan['Name'] ?? '',
                            'alias' => $plan['PlanAlias'] ?? '',
                            'diskQuota' => $plan['DiskQuota'] ?? 0,
                            'bandwidth' => $plan['Bandwidth'] ?? 0,
                            'maxDomainAlias' => $plan['MaxDomainAlias'] ?? 0,
                            'maxSubDomain' => $plan['MaxSubDomain'] ?? 0,
                            'maxMailBox' => $plan['MaxMailBox'] ?? 0,
                            'maxDatabase' => $plan['MaxDatabase'] ?? 0,
                            'maxFtpUser' => $plan['MaxFtpUser'] ?? 0,
                        ];
                    }
                }

                return [
                    'status' => 'success',
                    'message' => __('admin/modules.maestropanel_list_plans_success'),
                    'data' => $plans,
                ];

            case 'domain_details':
                if (empty($params['domain'])) {
                    return [
                        'status' => 'error',
                        'message' => __('admin/modules.maestropanel_domain_required'),
                    ];
                }

                $response = $this->callApi('/Domain/GetDomainDetail', 'GET', [
                    'name' => $params['domain'],
                ], $params);

                if (! isset($response['Code']) || $response['Code'] !== 0) {
                    return [
                        'status' => 'error',
                        'message' => $response['Message'] ?? __('admin/modules.maestropanel_domain_details_failed'),
                    ];
                }

                $details = $response['Details'] ?? [];

                return [
                    'status' => 'success',
                    'message' => __('admin/modules.maestropanel_domain_details_success'),
                    'data' => [
                        'name' => $details['Name'] ?? '',
                        'username' => $details['Username'] ?? '',
                        'status' => $details['Status'] ?? '',
                        'planAlias' => $details['PlanAlias'] ?? '',
                        'diskUsage' => $details['DiskUsage'] ?? 0,
                        'bandwidthUsage' => $details['BandwidthUsage'] ?? 0,
                        'diskQuota' => $details['DiskQuota'] ?? 0,
                        'bandwidth' => $details['Bandwidth'] ?? 0,
                        'expirationDate' => $details['ExpirationDate'] ?? '',
                    ],
                ];

            default:
                return [
                    'status' => 'error',
                    'message' => __('admin/modules.maestropanel_action_not_supported', ['action' => $action]),
                ];
        }
    }

    // =========================================================================
    // CLIENT ACTIONS
    // =========================================================================

    /**
     * Client area action definitions.
     *
     * @return array Client actions
     */
    public function getClientActions(): array
    {
        $actions = parent::getClientActions();

        $actions['login_panel'] = [
            'label' => __('admin/modules.maestropanel_action_login_panel'),
            'icon' => 'fas fa-sign-in-alt',
            'class' => 'btn-outline-primary',
            'enabled' => true,
        ];

        return $actions;
    }

    /**
     * Handle client action.
     *
     * @param  string  $action  Action name
     * @param  array  $params  Parameters
     * @return array Result
     */
    public function handleClientAction(string $action, array $params): array
    {
        switch ($action) {
            case 'login_panel':
                return $this->generatePanelLoginUrl($params);

            case 'change_password':
                return $this->changeAccountPassword($params);

            default:
                return parent::handleClientAction($action, $params);
        }
    }

    /**
     * Generate MaestroPanel SSO login for a client (domain user).
     *
     * MaestroPanel SSO gerçek endpoint'i `:9715/Auth/SignOn`'a POST auto-submit
     * form'dur (username+password gövdede). Bare base-URL oturum AÇMAZ. Resmî
     * WHMCS modülü ile birebir: hidden username/password + auto-submit.
     *
     * Client için username = domain (WHMCS `maestropanel_clientarea` hostingaccount
     * dalı domain'i kullanıcı adı olarak yollar), password = hesap parolası.
     *
     * @param  array  $params  Parameters (domain required)
     * @return array Result with auto-submit SSO form HTML
     */
    protected function generatePanelLoginUrl(array $params): array
    {
        if (empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_domain_required'),
            ];
        }

        $server = $this->serverConfig($params);

        $hostname = $server['hostname'];
        if ($hostname === '') {
            return [
                'status' => 'error',
                'message' => __('admin/modules.maestropanel_config_hostname_missing'),
            ];
        }

        $protocol = $server['secure'] ? 'https' : 'http';
        $port = ! empty($server['port']) ? $server['port'] : $this->apiPort;

        $signOnUrl = "{$protocol}://{$hostname}:{$port}/Auth/SignOn";

        // Resmî modülde hostingaccount SSO username=domain; password=hesap parolası.
        $username = (string) $params['domain'];
        $password = (string) ($params['password'] ?? '');

        return [
            'status' => 'success',
            'message' => __('admin/modules.maestropanel_login_url_generated'),
            'url' => $signOnUrl,
            'html' => $this->buildSsoForm($signOnUrl, $username, $password),
        ];
    }

    /**
     * Build an auto-submit SSO form (POST) to MaestroPanel /Auth/SignOn.
     *
     * @param  string  $method  HTTP method for the form (post for domain user,
     *                          get for admin-root per resmî modül)
     */
    protected function buildSsoForm(string $actionUrl, string $username, string $password, string $method = 'post'): string
    {
        $action = htmlspecialchars($actionUrl, ENT_QUOTES, 'UTF-8');
        $user = htmlspecialchars($username, ENT_QUOTES, 'UTF-8');
        $pass = htmlspecialchars($password, ENT_QUOTES, 'UTF-8');
        $method = strtolower($method) === 'get' ? 'get' : 'post';

        return '<form id="maestropanel-sso" action="' . $action . '" method="' . $method . '" target="_blank">'
            . '<input type="hidden" name="username" value="' . $user . '">'
            . '<input type="hidden" name="password" value="' . $pass . '">'
            . '</form>'
            . '<script>document.getElementById("maestropanel-sso").submit();</script>';
    }

    // =========================================================================
    // RESOURCE USAGE
    // =========================================================================

    /**
     * Get resource usage from MaestroPanel.
     *
     * GET /Api/v1/Domain/GetLimits → RESULT.DETAILS.Limit[] içinde limit adları:
     *   - MSFTP_FTPQUOTA   → disk kotası (Usage/Limit)
     *   - IIS_LIMIT_TRAFFIC → trafik/bandwidth kotası (Usage/Limit)
     * Referans: WiseCP MaestroPanel modülü.
     *
     * @param  array  $params  Parameters (domain required)
     * @return array|null Resource usage data or null
     */
    public function getResourceUsage(array $params): ?array
    {
        if (empty($params['domain'])) {
            return null;
        }

        $response = $this->callApi('/Domain/GetLimits', 'GET', [
            'name' => $params['domain'],
        ], $params);

        if (! isset($response['Code']) || $response['Code'] !== 0) {
            return null;
        }

        $limits = $this->extractLimits($response['Details'] ?? []);

        $resources = [];

        // Disk — MSFTP_FTPQUOTA
        $disk = $limits['MSFTP_FTPQUOTA'] ?? ['used' => 0.0, 'limit' => 0.0];
        $resources[] = [
            'name' => 'Disk Space',
            'used' => $disk['used'],
            'limit' => $disk['limit'],
            'unit' => 'MB',
            'percentage' => $disk['limit'] > 0 ? round(($disk['used'] / $disk['limit']) * 100, 2) : 0,
        ];

        // Bandwidth — IIS_LIMIT_TRAFFIC
        $bw = $limits['IIS_LIMIT_TRAFFIC'] ?? ['used' => 0.0, 'limit' => 0.0];
        $resources[] = [
            'name' => 'Bandwidth',
            'used' => $bw['used'],
            'limit' => $bw['limit'],
            'unit' => 'MB',
            'percentage' => $bw['limit'] > 0 ? round(($bw['used'] / $bw['limit']) * 100, 2) : 0,
        ];

        return $resources;
    }

    /**
     * Normalize the GetLimits DETAILS payload into a name→{used,limit} map.
     *
     * XML→array dönüşümü tek eleman için düz, çok eleman için liste üretir;
     * her iki şekli de tolere eder.
     *
     * @param  array  $details  RESULT.DETAILS (may contain 'Limit' list or map)
     * @return array<string,array{used:float,limit:float}>
     */
    protected function extractLimits(array $details): array
    {
        $rows = $details['Limit'] ?? $details;

        // Tek limit satırı düz assoc gelebilir → listeye sar.
        if (isset($rows['Name']) || isset($rows['name'])) {
            $rows = [$rows];
        }

        $out = [];
        foreach ((array) $rows as $row) {
            if (! is_array($row)) {
                continue;
            }
            $name = (string) ($row['Name'] ?? $row['name'] ?? '');
            if ($name === '') {
                continue;
            }
            $out[$name] = [
                'used' => (float) ($row['Usage'] ?? $row['usage'] ?? $row['Used'] ?? 0),
                'limit' => (float) ($row['Limit'] ?? $row['limit'] ?? $row['Value'] ?? 0),
            ];
        }

        return $out;
    }

    // =========================================================================
    // API COMMUNICATION
    // =========================================================================

    /**
     * Make an API call to MaestroPanel REST API.
     *
     * Resmî sözleşme (WHMCS `maestropanel.php` + resmî PHP API sample ile birebir):
     *   - Base URL:  http(s)://{hostname}:{port}/Api/v1/{action}
     *   - Auth:      `key` istek GÖVDESİNDE, form-encoded packet içinde
     *                (POST/DELETE); GET-style eylemlerde query string.
     *   - Gövde:     application/x-www-form-urlencoded (http_build_query)
     *   - Yanıt:     XML → array; başarı = RESULT.ERRORCODE == 0, hata = RESULT.MESSAGE
     *
     * PRC-1015: host/creds DAİMA serverConfig($params) ile çözülür (atanmış
     * sunucu öncelikli). api_key panel admin API anahtarıdır; serverConfig
     * password alanına map'ler. api-key ASLA loglanmaz.
     *
     * Dönüş normalize edilir → mevcut çağrı yerleri `Code`/`Message`/`Details`
     * beklemeye devam eder: Code = (int) ERRORCODE, Message = MESSAGE,
     * Details = DETAILS.
     *
     * @param  string  $endpoint  API endpoint (e.g. /Domain/Create)
     * @param  string  $method  HTTP method (GET, POST, DELETE)
     * @param  array  $data  Request data (key hariç; key burada eklenir)
     * @param  array  $params  Provisioning params (server/module_config kaynağı)
     * @return array Normalized response: ['Code'=>int,'Message'=>string,'Details'=>mixed]
     */
    protected function callApi($endpoint, $method = 'GET', $data = [], array $params = [])
    {
        $server = $this->serverConfig($params);

        $protocol = $server['secure'] ? 'https' : 'http';
        $hostname = $server['hostname'];
        $port = ! empty($server['port']) ? $server['port'] : $this->apiPort;
        $apiKey = $server['password'];

        if ($hostname === '' || $apiKey === '') {
            return [
                'Code' => -1,
                'Message' => __('admin/modules.maestropanel_config_hostname_missing'),
            ];
        }

        $url = "{$protocol}://{$hostname}:{$port}/{$this->apiVersion}{$endpoint}";

        // key DAİMA packet'e (gövde/query) dahil edilir — resmî auth sözleşmesi.
        $packet = array_merge(['key' => $apiKey], $data);
        $body = http_build_query($packet);

        $method = strtoupper($method);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        // MaestroPanel API portu (9715) tipik olarak self-signed sertifika sunar;
        // resmî WHMCS/PHP modülleri de verify kapalı çalışır (aksi halde bağlantı
        // kopar). TLS-verify açmak canlı kurulumları kırar — bkz. residual.
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/x-www-form-urlencoded',
            'Accept: application/xml, text/xml',
        ]);

        switch ($method) {
            case 'GET':
                // GET-style: packet (key dahil) query string'e gider.
                curl_setopt($ch, CURLOPT_URL, $url . '?' . $body);
                break;

            case 'DELETE':
                // Resmî modül Domain/Delete'i GET-style (query) + DELETE verb yollar.
                curl_setopt($ch, CURLOPT_URL, $url . '?' . $body);
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
                break;

            case 'POST':
            default:
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
                break;
        }

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

        curl_close($ch);

        if ($curlError) {
            return [
                'Code' => -1,
                'Message' => __('admin/modules.maestropanel_api_curl_error', ['error' => $curlError]),
            ];
        }

        if ($httpCode >= 400 || ! is_string($response) || trim($response) === '') {
            // PCI/güvenlik: ham API yanıtı zarfa/loga sızdırılmaz.
            return [
                'Code' => -1,
                'Message' => __('admin/modules.maestropanel_api_call_failed', ['code' => $httpCode]),
            ];
        }

        return $this->parseXmlResponse($response);
    }

    /**
     * Parse MaestroPanel XML response into normalized ['Code','Message','Details'].
     *
     * Beklenen zarf: <PACKET><RESULT><ERRORCODE>0</ERRORCODE><MESSAGE>..</MESSAGE>
     * <DETAILS>..</DETAILS></RESULT></PACKET>. RESULT sarmalayıcı yoksa köke
     * düşülür (bazı eylemler düz döndürebilir).
     */
    protected function parseXmlResponse(string $xml): array
    {
        $prev = libxml_use_internal_errors(true);
        $obj = simplexml_load_string($xml);
        libxml_clear_errors();
        libxml_use_internal_errors($prev);

        if ($obj === false) {
            return [
                'Code' => -1,
                'Message' => __('admin/modules.maestropanel_api_call_failed', ['code' => 'XML']),
            ];
        }

        $arr = json_decode(json_encode($obj), true);
        if (! is_array($arr)) {
            $arr = [];
        }

        // RESULT sarmalayıcısını normalize et (case-insensitive erişim için).
        $result = $arr['RESULT'] ?? $arr['Result'] ?? $arr;

        $errorCode = $result['ERRORCODE'] ?? $result['ErrorCode'] ?? $result['Code'] ?? null;
        $message = $result['MESSAGE'] ?? $result['Message'] ?? '';
        $details = $result['DETAILS'] ?? $result['Details'] ?? [];

        return [
            'Code' => is_numeric($errorCode) ? (int) $errorCode : -1,
            'Message' => is_string($message) ? $message : '',
            'Details' => $details,
        ];
    }

    /**
     * Derive a MaestroPanel account username from a domain name.
     *
     * WiseCP UsernameGenerator davranışı: alfanumerik'e indir, 3-16 char,
     * harfle başlat. Boşsa random üret.
     */
    protected function generateUsername(string $domain): string
    {
        $base = strtolower(preg_replace('/[^a-z0-9]/i', '', explode('.', $domain)[0] ?? ''));

        if ($base === '' || ! ctype_alpha($base[0])) {
            $base = 'u' . $base;
        }

        $base = substr($base, 0, 12);

        // Çakışma riskini azaltmak için kısa rastgele son ek.
        return $base . substr((string) random_int(100, 999), 0, 3);
    }

    /**
     * Generate a strong password meeting MaestroPanel's min requirement
     * (>= 8 char, >= 2 non-alphanumeric). Resmî PHP sample bunu zorunlu kılar.
     */
    protected function generatePassword(int $length = 14): string
    {
        $upper = 'ABCDEFGHJKMNPQRSTUVWXYZ';
        $lower = 'abcdefghijkmnpqrstuvwxyz';
        $digits = '23456789';
        $special = '!@#$%^&*-_';

        $required = [
            $upper[random_int(0, strlen($upper) - 1)],
            $lower[random_int(0, strlen($lower) - 1)],
            $digits[random_int(0, strlen($digits) - 1)],
            $special[random_int(0, strlen($special) - 1)],
            $special[random_int(0, strlen($special) - 1)], // 2+ non-alphanumeric
        ];

        $all = $upper . $lower . $digits . $special;
        for ($i = count($required); $i < max($length, 8); $i++) {
            $required[] = $all[random_int(0, strlen($all) - 1)];
        }

        shuffle($required);

        return implode('', $required);
    }

    /**
     * Read a contact field from the flat builder aliases (PRC-1015).
     * İlk dolu alias'ı döndürür, yoksa boş string.
     *
     * @param  array<int,string>  $keys
     */
    protected function contactField(array $params, array $keys): string
    {
        foreach ($keys as $key) {
            if (isset($params[$key]) && is_scalar($params[$key]) && trim((string) $params[$key]) !== '') {
                return (string) $params[$key];
            }
        }

        return '';
    }

    // =========================================================================
    // CONFIGURATION VALIDATION
    // =========================================================================

    /**
     * Validate module configuration.
     *
     * @return bool Configuration is valid
     *
     * @throws \Exception When configuration is missing
     */
    public function validateConfig()
    {
        if (empty($this->config['hostname'])) {
            throw new \Exception(__('admin/modules.maestropanel_config_hostname_missing'));
        }

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

        return true;
    }
}
