<?php

namespace App\Core\Product;

abstract class AbstractProduct implements ProductInterface
{
    protected $config;

    public function __construct(array $config = [])
    {
        $this->config = $config;
    }

    // Zorunlu fonksiyonlar - alt sınıflar tarafından uygulanmalı
    abstract public function createAccount(array $params);

    abstract public function suspendAccount(array $params);

    abstract public function unsuspendAccount(array $params);

    abstract public function terminateAccount(array $params);

    abstract public function changeAccountPassword(array $params);

    // Opsiyonel fonksiyonlar için varsayılan implementasyonlar
    public function changeAccountPackage(array $params)
    {
        throw new \Exception('Bu işlev bu modülde desteklenmiyor.');
    }

    public function adminFields()
    {
        return [];
    }

    public function clientFields()
    {
        return [];
    }

    public function serverFields()
    {
        return [];
    }

    public function adminOutput(array $params)
    {
        return '';
    }

    public function clientOutput(array $params)
    {
        return '';
    }

    public function testConnection(array $params)
    {
        throw new \Exception('Bu işlev bu modülde desteklenmiyor.');
    }

    public function createSSOLogin(array $params)
    {
        throw new \Exception('Bu işlev bu modülde desteklenmiyor.');
    }

    /**
     * Default: modül mapping pipeline'ına katılmaz (boş schema). VM-tipinde
     * provider'lar (Hetzner, Proxmox vb.) override eder.
     */
    public function paramSchema(): array
    {
        return [];
    }

    // =========================================================================
    //  Param Contract Helpers — PRC-1015
    // =========================================================================

    /**
     * Panel/sunucu bağlantısı için tek doğru kaynak (host/creds).
     *
     * Modüller host/creds'i tutarsız okuyordu (`$this->config` vs
     * `$params['server']`) → server-based modülde atanmış sunucu yok sayılıyordu.
     * Bu helper tek kural: **atanmış sunucu (`$params['server']`) öncelikli**,
     * yoksa `module_config` (product module config / `$this->config`) fallback.
     * Böylece server-based modül atanmış sunucuya, serverless modül (api_key ile)
     * module_config'e bağlanır — ikisi de tek helper'dan.
     *
     * @return array{hostname:string,ip:string,port:mixed,username:string,password:string,secure:bool}
     */
    protected function serverConfig(array $params): array
    {
        $server = (isset($params['server']) && is_array($params['server'])) ? $params['server'] : [];
        $config = (isset($params['module_config']) && is_array($params['module_config']))
            ? $params['module_config']
            : (is_array($this->config) ? $this->config : []);

        // Atanmış sunucu öncelikli; her alan için sunucu → config sırayla taranır.
        $pick = function (array $keys, $default = '') use ($server, $config) {
            foreach ([$server, $config] as $source) {
                foreach ($keys as $key) {
                    if (isset($source[$key]) && is_scalar($source[$key]) && trim((string) $source[$key]) !== '') {
                        return $source[$key];
                    }
                }
            }

            return $default;
        };

        return [
            'hostname' => (string) $pick(['hostname', 'ip_address', 'server_name', 'host', 'server_host', 'ip']),
            'ip'       => (string) $pick(['ip_address', 'ip', 'hostname', 'host']),
            'port'     => $pick(['port'], null),
            'username' => (string) $pick(['username', 'user', 'api_user', 'login', 'admin_user']),
            'password' => (string) $pick(['password', 'api_key', 'apikey', 'api_token', 'token', 'access_hash', 'accesshash', 'secret', 'hash']),
            'secure'   => (bool) $pick(['secure', 'ssl', 'use_ssl'], true),
        ];
    }

    /**
     * Nested `config_options`'tan bir seçeneği adına göre (case-insensitive) okur.
     * Modüller `$params['config_options']` dizisini elle taramak yerine kullanır.
     *
     * @param  string  $name  Aranan option_name
     * @return mixed  Seçili değer (value_name → value_id) veya $default
     */
    protected function configOption(array $params, string $name, $default = null)
    {
        foreach (($params['config_options'] ?? []) as $option) {
            if (! is_array($option)) {
                continue;
            }
            if (isset($option['option_name']) && strcasecmp((string) $option['option_name'], $name) === 0) {
                $value = $option['value_name'] ?? $option['value_id'] ?? null;

                return ($value !== null && $value !== '') ? $value : $default;
            }
        }

        return $default;
    }

    /**
     * Uzak panel/VM hesap kimliği (PRC-1015 `server_id` çakışması fix).
     *
     * `server_id` iç procp Server FK'sidir — uzak-id DEĞİL. Modüller uzak hesabı
     * `account_id`/`module_handler_id`'den almalı. Bu helper doğru kaynağı verir.
     */
    protected function remoteId(array $params): ?string
    {
        foreach (['account_id', 'module_handler_id'] as $key) {
            if (isset($params[$key]) && is_scalar($params[$key]) && trim((string) $params[$key]) !== '') {
                return (string) $params[$key];
            }
        }

        return null;
    }

    /**
     * Product module-config'ten (admin-set) bir anahtar okur.
     * `$params['module_config']` öncelikli, yoksa `$this->config`.
     */
    protected function moduleConfig(array $params, string $key, $default = null)
    {
        $config = (isset($params['module_config']) && is_array($params['module_config']))
            ? $params['module_config']
            : (is_array($this->config) ? $this->config : []);

        return (isset($config[$key]) && $config[$key] !== '') ? $config[$key] : $default;
    }

    // Yardımcı metotlar
    protected function callApi($endpoint, $method = 'GET', $data = [])
    {
        // Ortak API çağrı kodu
    }

    public function validateConfig()
    {
        // Modül yapılandırmasını doğrulama
    }

    /**
     * Modülün desteklediği özellikleri döndürür
     */
    public function getFeatures(): array
    {
        return [
            'create_account' => method_exists($this, 'createAccount'),
            'suspend_account' => method_exists($this, 'suspendAccount'),
            'unsuspend_account' => method_exists($this, 'unsuspendAccount'),
            'terminate_account' => method_exists($this, 'terminateAccount'),
            'change_password' => method_exists($this, 'changeAccountPassword'),
            'change_package' => $this->hasRealImplementation('changeAccountPackage'),
            'test_connection' => $this->hasRealImplementation('testConnection'),
            'sso_login' => $this->hasRealImplementation('createSSOLogin'),
            'requires_server' => $this->requiresServer(),
            'admin_fields' => ! empty($this->adminFields()),
            'client_fields' => ! empty($this->clientFields()),
            'server_fields' => ! empty($this->serverFields()),
            'admin_output' => $this->hasRealAdminOutput(),
            'client_output' => $this->hasRealClientOutput(),
        ];
    }

    /**
     * Bir metodun gerçek implementasyona sahip olup olmadığını kontrol eder
     */
    private function hasRealImplementation($methodName): bool
    {
        try {
            $reflectionMethod = new \ReflectionMethod($this, $methodName);
            $declaringClass = $reflectionMethod->getDeclaringClass()->getName();

            return $declaringClass !== AbstractProduct::class;
        } catch (\ReflectionException $e) {
            return false;
        }
    }

    /**
     * adminOutput metodunun gerçek bir implementasyona sahip olup olmadığını kontrol eder
     */
    private function hasRealAdminOutput(): bool
    {
        return $this->hasRealImplementation('adminOutput') || ! empty($this->adminOutput([]));
    }

    /**
     * clientOutput metodunun gerçek bir implementasyona sahip olup olmadığını kontrol eder
     */
    private function hasRealClientOutput(): bool
    {
        return $this->hasRealImplementation('clientOutput') || ! empty($this->clientOutput([]));
    }

    /**
     * Modülün server gerektirip gerektirmediğini döndürür
     * Alt sınıflar bu metodu override ederek server gerekliliğini belirtebilir
     */
    public function requiresServer(): bool
    {
        return true; // Varsayılan olarak server gerektirir
    }

    /**
     * Admin panelde gösterilecek özel butonları döndürür
     *
     * Format:
     * [
     *     [
     *         'action' => 'restart_service',
     *         'label' => 'Servisi Yeniden Başlat',
     *         'icon' => 'fas fa-sync',
     *         'class' => 'btn-outline-warning'
     *     ],
     *     [
     *         'action' => 'check_status',
     *         'label' => 'Durum Kontrol',
     *         'icon' => 'fas fa-check-circle',
     *         'class' => 'btn-outline-info'
     *     ]
     * ]
     */
    public function getAdminButtons(): array
    {
        return [];
    }

    /**
     * Admin özel action'ı işler
     *
     * @param  string  $action  Action adı
     * @param  array  $params  Parametreler
     * @return array İşlem sonucu
     */
    public function adminCustomAction(string $action, array $params): array
    {
        throw new \Exception("Admin action '{$action}' bu modülde desteklenmiyor.");
    }

    /**
     * Client area'da gösterilecek action'ları döndürür
     *
     * Format:
     * [
     *     'change_password' => [
     *         'label' => 'Şifre Değiştir',
     *         'icon' => 'fas fa-key',
     *         'class' => 'btn-primary',
     *         'enabled' => true
     *     ],
     *     'custom_action' => [
     *         'label' => 'Özel İşlem',
     *         'icon' => 'fas fa-cog',
     *         'class' => 'btn-info',
     *         'enabled' => true
     *     ]
     * ]
     */
    public function getClientActions(): array
    {
        $actions = [];

        // Şifre değiştirme action'ı - tüm modüller için varsayılan
        if (method_exists($this, 'changeAccountPassword')) {
            $actions['change_password'] = [
                'label' => 'Şifre Değiştir',
                'icon' => 'fas fa-key',
                'class' => 'btn-outline-primary',
                'enabled' => true,
            ];
        }

        return $actions;
    }

    /**
     * Kaynak kullanım bilgilerini döndürür (disk, bandwidth, email, database vb.)
     *
     * Alt sınıflar bu metodu override ederek gerçek sunucudan veri çekebilir.
     * Varsayılan olarak null döndürür (veri yok).
     *
     * Format:
     * [
     *     [
     *         'name' => 'Disk Space',
     *         'used' => 2048,
     *         'limit' => 10240,
     *         'unit' => 'MB',
     *         'percentage' => 20.0,
     *     ],
     *     [
     *         'name' => 'Bandwidth',
     *         'used' => 50,
     *         'limit' => 100,
     *         'unit' => 'GB',
     *         'percentage' => 50.0,
     *     ],
     * ]
     *
     * @param  array  $params  Parametreler (service_id, username, domain, module_config vb.)
     * @return array|null Kaynak kullanım verileri veya null
     */
    public function getResourceUsage(array $params): ?array
    {
        return null;
    }

    /**
     * Client action'ı işler
     *
     * @param  string  $action  Action adı
     * @param  array  $params  Parametreler
     * @return array Sonuç
     */
    public function handleClientAction(string $action, array $params): array
    {
        switch ($action) {
            case 'change_password':
                return $this->changeAccountPassword($params);
            default:
                return [
                    'status' => 'error',
                    'message' => 'Bu işlem desteklenmiyor.',
                ];
        }
    }
}
