<?php

namespace App\Modules\Product\Cyberpanel;

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

class Cyberpanel extends AbstractProduct
{
    /**
     * Default CyberPanel API port
     */
    protected $apiPort = 8090;

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

    /**
     * Creates a new CyberPanel website/account
     *
     * Uses CyberPanel API: POST /api/createWebsite
     *
     * @param  array  $params  Parameters (domain, username, password, email, plan)
     * @return array Operation result
     */
    public function createAccount(array $params)
    {
        $requiredParams = [
            'username', 'password', 'domain',
        ];

        foreach ($requiredParams as $param) {
            if (! isset($params[$param]) || empty($params[$param])) {
                return [
                    'status' => 'error',
                    'message' => __('admin/modules.cyberpanel_param_missing', ['param' => $param]),
                ];
            }
        }

        // PRC-1015: package/plan flat ($params['plan']/$params['package']) —
        // builder module-config'ten emit eder; yoksa module_config fallback.
        $package = $params['plan']
            ?? $params['package']
            ?? $this->moduleConfig($params, 'default_package', 'Default');
        $phpVersion = $params['php_version'] ?? $this->moduleConfig($params, 'php_version', 'PHP 8.1');
        // Builder emits `client_email`; `email` only if a clientFields value merged in.
        $email = $params['client_email'] ?? $params['email'] ?? '';

        $postData = [
            'domainName' => $params['domain'],
            'ownerEmail' => $email,
            // CyberPanel createWebsite expects `packageName` (WiseCP api.php:74);
            // an unknown `package` key is silently dropped → server default package.
            'packageName' => $package,
            'websiteOwner' => $params['username'],
            'ownerPassword' => $params['password'],
            'websitesLimit' => $params['websites_limit'] ?? 1,
            'acl' => $params['acl'] ?? 'user',
            'phpSelection' => $phpVersion,
            'ssl' => $params['ssl'] ?? 1,
            'dkimCheck' => $params['dkim'] ?? 0,
            'openBasedir' => $params['open_basedir'] ?? 1,
        ];

        $response = $this->callCyberPanelApi('/api/createWebsite', $postData, $params);

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

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

            return $result;
        }

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

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

        return $result;
    }

    /**
     * Suspends a CyberPanel website
     *
     * Uses CyberPanel API: POST /api/submitWebsiteStatus with state=Suspend
     *
     * @param  array  $params  Parameters (domain)
     * @return array Operation result
     */
    public function suspendAccount(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.cyberpanel_domain_required'),
            ];
        }

        $postData = [
            'websiteName' => $params['domain'],
            'state' => 'Suspend',
        ];

        $response = $this->callCyberPanelApi('/api/submitWebsiteStatus', $postData, $params);

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

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

    /**
     * Unsuspends a CyberPanel website
     *
     * Uses CyberPanel API: POST /api/submitWebsiteStatus with state=Activate
     *
     * @param  array  $params  Parameters (domain)
     * @return array Operation result
     */
    public function unsuspendAccount(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.cyberpanel_domain_required'),
            ];
        }

        // CyberPanel submitWebsiteStatus expects `Activate` (WiseCP decoded
        // change_account_status → "Activate"); `Active` is unrecognized → no-op.
        $postData = [
            'websiteName' => $params['domain'],
            'state' => 'Activate',
        ];

        $response = $this->callCyberPanelApi('/api/submitWebsiteStatus', $postData, $params);

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

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

    /**
     * Terminates (deletes) a CyberPanel website
     *
     * Uses CyberPanel API: POST /api/deleteWebsite
     *
     * @param  array  $params  Parameters (domain)
     * @return array Operation result
     */
    public function terminateAccount(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.cyberpanel_domain_required'),
            ];
        }

        $postData = [
            'domainName' => $params['domain'],
        ];

        $response = $this->callCyberPanelApi('/api/deleteWebsite', $postData, $params);

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

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

    /**
     * Changes a CyberPanel user's password
     *
     * Uses CyberPanel API: POST /api/changeUserPassAPI
     *
     * @param  array  $params  Parameters (username, password)
     * @return array Operation result
     */
    public function changeAccountPassword(array $params)
    {
        if (! isset($params['username']) || empty($params['username'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.cyberpanel_username_required'),
            ];
        }

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

        $postData = [
            'websiteOwner' => $params['username'],
            'ownerPassword' => $params['password'],
        ];

        $response = $this->callCyberPanelApi('/api/changeUserPassAPI', $postData, $params);

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

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

    /**
     * Changes the package for a CyberPanel website
     *
     * Uses CyberPanel API: POST /api/changePackageAPI
     *
     * @param  array  $params  Parameters (domain, plan)
     * @return array Operation result
     */
    public function changeAccountPackage(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.cyberpanel_domain_required'),
            ];
        }

        // PRC-1015: package/plan flat — builder emit eder; fallback module_config.
        $package = $params['plan']
            ?? $params['package']
            ?? $this->moduleConfig($params, 'default_package', null);

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

        $postData = [
            'websiteName' => $params['domain'],
            'packageName' => $package,
        ];

        $response = $this->callCyberPanelApi('/api/changePackageAPI', $postData, $params);

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

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

    /**
     * Tests the connection to the CyberPanel server
     *
     * Uses CyberPanel API: POST /api/verifyConn to verify connectivity
     * (WiseCP api.php:102 — takes only adminUser/adminPass, returns status==1).
     *
     * @param  array  $params  Test parameters
     * @return array Test result
     */
    public function testConnection(array $params = [])
    {
        $response = $this->callCyberPanelApi('/api/verifyConn', [], $params);

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

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

    /**
     * Creates an SSO login URL for CyberPanel
     *
     * CyberPanel does not have a native SSO/session token API,
     * so this returns the direct panel login URL for the user.
     *
     * @param  array  $params  Parameters (domain)
     * @return array Operation result with panel URL
     */
    public function createSSOLogin(array $params)
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return [
                'status' => 'error',
                'message' => __('admin/modules.cyberpanel_domain_required'),
            ];
        }

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

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

        $panelUrl = "{$protocol}://{$hostname}:{$port}";

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

    /**
     * Returns admin panel configuration fields
     *
     * @return array Admin panel fields
     */
    public function adminFields()
    {
        return [
            'hostname' => [
                'name' => __('admin/modules.cyberpanel_field_hostname'),
                'type' => 'text',
                'description' => __('admin/modules.cyberpanel_field_hostname_description'),
                'required' => true,
            ],
            'port' => [
                'name' => __('admin/modules.cyberpanel_field_port'),
                'type' => 'text',
                'description' => __('admin/modules.cyberpanel_field_port_description'),
                'required' => false,
                'default' => '8090',
            ],
            'username' => [
                'name' => __('admin/modules.cyberpanel_field_username'),
                'type' => 'text',
                'description' => __('admin/modules.cyberpanel_field_username_description'),
                'required' => true,
            ],
            'password' => [
                'name' => __('admin/modules.cyberpanel_field_password'),
                'type' => 'password',
                'description' => __('admin/modules.cyberpanel_field_password_description'),
                'required' => true,
            ],
            'default_package' => [
                'name' => __('admin/modules.cyberpanel_field_default_package'),
                'type' => 'text',
                'description' => __('admin/modules.cyberpanel_field_default_package_description'),
                'required' => false,
                'default' => 'Default',
            ],
            'php_version' => [
                'name' => __('admin/modules.cyberpanel_field_php_version'),
                'type' => 'text',
                'description' => __('admin/modules.cyberpanel_field_php_version_description'),
                'required' => false,
                'default' => 'PHP 8.1',
            ],
            'secure' => [
                'name' => __('admin/modules.cyberpanel_field_secure'),
                'type' => 'checkbox',
                'description' => __('admin/modules.cyberpanel_field_secure_description'),
                'default' => true,
            ],
        ];
    }

    /**
     * Returns client panel fields
     *
     * @return array Client panel fields
     */
    public function clientFields()
    {
        return [
            'domain' => [
                'name' => __('admin/modules.cyberpanel_field_domain'),
                'type' => 'text',
                'description' => __('admin/modules.cyberpanel_field_domain_description'),
                'required' => true,
            ],
            'username' => [
                'name' => __('admin/modules.cyberpanel_field_client_username'),
                'type' => 'text',
                'description' => __('admin/modules.cyberpanel_field_client_username_description'),
                'required' => true,
            ],
            'password' => [
                'name' => __('admin/modules.cyberpanel_field_client_password'),
                'type' => 'password',
                'description' => __('admin/modules.cyberpanel_field_client_password_description'),
                'required' => true,
            ],
            'email' => [
                'name' => __('admin/modules.cyberpanel_field_client_email'),
                'type' => 'text',
                'description' => __('admin/modules.cyberpanel_field_client_email_description'),
                'required' => false,
            ],
        ];
    }

    /**
     * Returns server management fields
     *
     * @return array Server management fields
     */
    public function serverFields()
    {
        return [
            'password' => [
                'name' => __('admin/modules.cyberpanel_field_password'),
                'type' => 'password',
                'description' => __('admin/modules.cyberpanel_field_password_description'),
                'required' => true,
            ],
        ];
    }

    /**
     * Validates the module configuration
     *
     * @return bool True if configuration is valid
     *
     * @throws \Exception When configuration is missing required values
     */
    public function validateConfig()
    {
        // Resolve via the unified helper (assigned server → module_config →
        // $this->config fallback) so validation matches callCyberPanelApi's
        // connection source instead of reading $this->config inline.
        $server = $this->serverConfig([]);

        if (empty($server['hostname'])) {
            throw new \Exception(__('admin/modules.cyberpanel_config_hostname_missing'));
        }

        if ($server['username'] === '') {
            throw new \Exception(__('admin/modules.cyberpanel_config_username_missing'));
        }

        if ($server['password'] === '') {
            throw new \Exception(__('admin/modules.cyberpanel_config_password_missing'));
        }

        return true;
    }

    /**
     * Returns resource usage information for a CyberPanel website
     *
     * @param  array  $params  Parameters (domain, username)
     * @return array|null Resource usage data or null
     */
    public function getResourceUsage(array $params): ?array
    {
        if (! isset($params['domain']) || empty($params['domain'])) {
            return null;
        }

        $postData = [
            'websiteName' => $params['domain'],
        ];

        $response = $this->callCyberPanelApi('/api/fetchWebsiteData', $postData, $params);

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

        $resources = [];

        if (isset($response['diskUsed'])) {
            $diskUsed = (float) $response['diskUsed'];
            $diskLimit = isset($response['diskLimit']) ? (float) $response['diskLimit'] : 0;
            $diskPercentage = $diskLimit > 0 ? round(($diskUsed / $diskLimit) * 100, 2) : 0;

            $resources[] = [
                'name' => __('admin/modules.cyberpanel_resource_disk_space'),
                'used' => $diskUsed,
                'limit' => $diskLimit,
                'unit' => 'MB',
                'percentage' => $diskPercentage,
            ];
        }

        if (isset($response['bandwidthUsed'])) {
            $bwUsed = (float) $response['bandwidthUsed'];
            $bwLimit = isset($response['bandwidthLimit']) ? (float) $response['bandwidthLimit'] : 0;
            $bwPercentage = $bwLimit > 0 ? round(($bwUsed / $bwLimit) * 100, 2) : 0;

            $resources[] = [
                'name' => __('admin/modules.cyberpanel_resource_bandwidth'),
                'used' => $bwUsed,
                'limit' => $bwLimit,
                'unit' => 'GB',
                'percentage' => $bwPercentage,
            ];
        }

        return ! empty($resources) ? $resources : null;
    }

    /**
     * Core API method: Makes a POST JSON request to the CyberPanel API
     *
     * CyberPanel API authenticates via adminUser and adminPass in the JSON body.
     * All endpoints accept POST with JSON content type.
     * Response format: { "status": 1, ... } for success, { "status": 0, "error_message": "..." } for error.
     *
     * PRC-1015: host/creds DAİMA $this->serverConfig($params) ile alınır
     * (atanmış sunucu öncelikli, yoksa module_config/$this->config fallback).
     * Inline $this->config[...] okuma yok. password/adminPass ASLA loglanmaz.
     *
     * @param  string  $endpoint  API endpoint (e.g., /api/createWebsite)
     * @param  array  $data  Additional data to send
     * @param  array  $params  Full module params (assigned server + module_config)
     * @return array API response
     */
    protected function callCyberPanelApi(string $endpoint, array $data = [], array $params = [])
    {
        $server = $this->serverConfig($params);

        $protocol = $server['secure'] ? 'https' : 'http';
        $port = $server['port'] ?: $this->apiPort;
        $hostname = $server['hostname'];

        if (empty($hostname) || $server['username'] === '' || $server['password'] === '') {
            return [
                'status' => 0,
                'error_message' => __('admin/modules.cyberpanel_config_hostname_missing'),
            ];
        }

        $url = "{$protocol}://{$hostname}:{$port}{$endpoint}";

        // CyberPanel authenticates via adminUser/adminPass in the JSON body
        $requestData = array_merge([
            'adminUser' => $server['username'],
            'adminPass' => $server['password'],
        ], $data);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($requestData));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Accept: application/json',
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);

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

        curl_close($ch);

        // Handle cURL errors
        if ($curlError) {
            return [
                'status' => 0,
                'error_message' => __('admin/modules.cyberpanel_curl_error', ['error' => $curlError]),
            ];
        }

        // Parse JSON response
        $responseData = json_decode($response, true);

        // Handle HTTP errors or invalid JSON. Raw panel output is NOT echoed
        // back (may carry sensitive data — PCI/PRC-1015).
        if ($httpCode >= 400 || ! is_array($responseData)) {
            return [
                'status' => 0,
                'error_message' => __('admin/modules.cyberpanel_api_call_failed', ['code' => $httpCode]),
            ];
        }

        return $responseData;
    }
}
