<?php

namespace App\Core\Product;

use App\Models\ClientProduct;
use Illuminate\Support\Facades\Log;

/**
 * Module Params Builder
 *
 * Product modüllerine (Dummyproduct, cPanel, Plesk, vb.) iletilen $params
 * array'ini merkezi ve tutarlı biçimde kurar. WHMCS'in sample provisioning
 * modülünün $params yapısından ilham alır:
 * https://github.com/WHMCS/sample-provisioning-module
 *
 * Caller (ProductProvisioningService, ProcessProductSuspendJob, vb.) yerine
 * inline param build etmek yerine şunu kullanmalı:
 *
 *     $params = ModuleParamsBuilder::build($clientProduct, [
 *         'reason' => 'Admin tarafından askıya alındı',
 *     ]);
 *     $module->suspendAccount($params);
 *
 * $extras, base context'i OVERRIDE eder — caller action-specific data
 * (yeni şifre, reason, yeni plan vb.) ekleyebilir veya değiştirebilir.
 */
class ModuleParamsBuilder
{
    /**
     * ClientProduct üzerinden WHMCS-esque full $params array'ini kurar.
     *
     * @param  ClientProduct  $cp  Servis kaydı
     * @param  array  $extras  Action-specific data (reason, new password, plan, vb.)
     * @return array
     */
    public static function build(ClientProduct $cp, array $extras = []): array
    {
        // Relation'ları eager load et (eksik olanları)
        $cp->loadMissing([
            'client.country',
            'product',
            'server',
            'configOptionValues.option',
            'configOptionValues.selectedValue',
            'configFieldValues.customField',
        ]);

        $client = $cp->client;
        $product = $cp->product;
        $server = $cp->server;

        // Service şifresi (decrypted) — DB'deki mevcut password
        $currentPassword = self::safeDecrypt($cp->password);

        // Admin-set module config (server_name, api_key, package/plan, vb.)
        $moduleConfig = $product && $product->module
            ? $product->getModuleConfigArray($product->module)
            : [];

        // PRC-1015: hosting package/plan adı module-config'ten (per-product).
        $package = self::resolvePackage($moduleConfig);

        $params = [
            // === Service identity ===
            'service_id' => $cp->id,
            'client_product_id' => $cp->id,
            'status' => $cp->status,
            'domain' => $cp->domain,
            'username' => $cp->username,
            'password' => $currentPassword,
            'account_id' => $cp->module_handler_id,
            'module_handler_id' => $cp->module_handler_id,
            // PRC-1064: VM ailesi uzak-id'yi buradan okur. vm_id create'te
            // module_data['vm_id']'e yazılır; her lifecycle caller'ın ayrı ayrı
            // 'module_data' extra'sı geçmesini beklemek yerine tek kaynaktan
            // emit et (suspend/unsuspend job + customAction controller vm_id'siz
            // kalıyordu → 'vm_id required' fail).
            'module_data' => is_array($cp->module_data) ? $cp->module_data : [],
            'vm_id' => (is_array($cp->module_data) ? ($cp->module_data['vm_id'] ?? null) : null) ?? $cp->module_handler_id,
            'billing_cycle' => $cp->billingcycle,
            'quantity' => $cp->quantity,
            'dedicated_ip' => $cp->dedicated_ip,
            'notes' => $cp->notes,
            'create_date' => optional($cp->create_date)?->format('Y-m-d'),
            'next_due_date' => optional($cp->next_due_date)?->format('Y-m-d'),
            'expire_date' => optional($cp->expire_date)?->format('Y-m-d'),
            'activation_date' => optional($cp->activation_date)?->format('Y-m-d H:i:s'),
            'suspend_date' => optional($cp->suspend_date)?->format('Y-m-d H:i:s'),

            // === Flat aliases (PRC-1015) — çok sayıda panel modülü flat
            // `email`/`first_name`/`last_name` hard-require ediyor; builder emit
            // etmezse createAccount param-gate'te düşüyor. `package`/`plan` ise
            // AŞAĞIDA koşullu eklenir (boşsa hiç eklenmez — bkz. not).
            'email' => $client?->email,
            'first_name' => $client?->first_name,
            'last_name' => $client?->last_name,

            // === Client (flat, WHMCS-style) ===
            'client_id' => $client?->id,
            'client_email' => $client?->email,
            'client_first_name' => $client?->first_name,
            'client_last_name' => $client?->last_name,
            'client_company' => $client?->company_name,
            'client_phone' => $client?->phone,
            'client_address1' => $client?->address1,
            'client_address2' => $client?->address2,
            'client_city' => $client?->city_id,
            'client_state' => $client?->state,
            'client_postcode' => $client?->postcode,
            'client_country_id' => $client?->country_id,
            'client_country_code' => $client?->country?->a2_iso,
            'client_language_id' => $client?->language_id,
            'client_currency_id' => $client?->currency_id,
            'client_group_id' => $client?->group_id,

            // === Product ===
            'product_id' => $product?->id,
            'product_name' => $product?->name,
            'product_type' => $product?->type,
            'product_module' => $product?->module,
            'product_slug' => $product?->slug,
            'product_group_id' => $product?->group_id,

            // === Server (nested) — decrypted credentials ===
            'server_id' => $cp->server_id,
            'server' => $server ? [
                'id' => $server->id,
                'name' => $server->name,
                'hostname' => $server->hostname,
                'ip_address' => $server->ip_address,
                'port' => $server->port,
                'module' => $server->module,
                'username' => $server->username,
                'password' => self::safeDecrypt($server->password),
                'status' => $server->status,
                'maximum_hosts' => $server->maximum_hosts,
                'current_hosts' => $server->current_hosts,
            ] : null,

            // === Custom fields ===
            // [{field_id, field_name, value}]
            'custom_fields' => $cp->configFieldValues
                ->map(fn ($cfv) => [
                    'field_id' => $cfv->option_id,
                    'field_name' => $cfv->customField?->label ?? $cfv->customField?->name,
                    'value' => $cfv->value,
                ])
                ->values()
                ->toArray(),

            // === Configurable options ===
            // [{option_id, option_name, value_id, value_name, group_id}]
            'config_options' => $cp->configOptionValues
                ->map(fn ($cov) => [
                    'option_id' => $cov->option_id,
                    'option_name' => $cov->option?->name,
                    'value_id' => $cov->value,
                    'value_name' => $cov->selectedValue?->value,
                    'group_id' => $cov->group_id,
                ])
                ->values()
                ->toArray(),

            // === Admin-set module config ===
            // (server_name, api_key, control_panel_url, package/plan, vb.)
            'module_config' => $moduleConfig,
        ];

        // PRC-1015: `package`/`plan`'ı YALNIZCA çözülebildiğinde emit et. Çözülemezse
        // anahtarı hiç ekleme — böylece modülün kendi `$params['plan'] ?? $this->
        // config['default_package']` fallback'i (absent → default) eskisi gibi çalışır.
        // Boş string ('') emit etmek `??`'yi atlatıp fallback'i öldürürdü (regresyon).
        if ($package !== '') {
            $params['package'] = $package;
            $params['plan'] = $package;
        }

        // $extras base context'i OVERRIDE eder.
        // Böylece caller yeni şifre, reason, plan gibi action-specific alanları
        // hem yeni ekleyebilir hem de override edebilir.
        return array_merge($params, $extras);
    }

    /**
     * Hosting package/plan adını module-config'ten çözer (PRC-1015 kararı:
     * package kaynağı per-product module-config). İlk non-empty scalar kazanır;
     * konfigüre edilmemişse '' döner (createAccount param-gate net hata verir).
     *
     * @param  array  $moduleConfig  Ürün modül config'i (field_key => field_value)
     */
    private static function resolvePackage(array $moduleConfig): string
    {
        // Modüllerin gerçekte kullandığı config anahtarları dahil (default_package/
        // default_plan/whm_package_name — grep ile doğrulandı); ilk non-empty kazanır.
        $keys = ['package', 'plan', 'package_name', 'plan_name', 'default_package', 'default_plan', 'whm_package_name'];
        foreach ($keys as $key) {
            if (isset($moduleConfig[$key]) && is_scalar($moduleConfig[$key]) && trim((string) $moduleConfig[$key]) !== '') {
                return trim((string) $moduleConfig[$key]);
            }
        }

        return '';
    }

    /**
     * Encrypted bir değeri güvenli decrypt eder — hata durumunda orijinal
     * değeri döndürür (plain text stored old data için fallback).
     */
    private static function safeDecrypt(?string $value): ?string
    {
        if (empty($value)) {
            return null;
        }

        try {
            return decrypt($value);
        } catch (\Throwable $e) {
            return $value;
        }
    }
}
