<?php

namespace App\Core\Email;

use App\Core\Module\ConfigFieldNormalizer;
use App\Core\Module\ManageableModuleManager;
use App\Core\Module\TestResult;
use App\Models\Setting;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;

class EmailManager implements ManageableModuleManager
{
    protected $providers = [];

    protected $activeProvider = null;

    public function __construct()
    {
        $this->loadProviders();
        $this->setActiveProvider();
    }

    /**
     * Provider'ları yükler
     */
    private function loadProviders()
    {
        $this->providers = [
            'smtp' => \App\Modules\Email\SMTP\SMTP::class,
            'mailgun' => \App\Modules\Email\Mailgun\Mailgun::class,
            'sendgrid' => \App\Modules\Email\SendGrid\SendGrid::class,
            // PRC-106 — additional transactional providers
            'postmark' => \App\Modules\Email\Postmark\Postmark::class,
            'mailjet' => \App\Modules\Email\Mailjet\Mailjet::class,
            'ses' => \App\Modules\Email\Ses\Ses::class,
            'brevo' => \App\Modules\Email\Brevo\Brevo::class,
            'sparkpost' => \App\Modules\Email\Sparkpost\Sparkpost::class,
            'mandrill' => \App\Modules\Email\Mandrill\Mandrill::class,
            'postal' => \App\Modules\Email\Postal\Postal::class,
            // PRC-759 — MailerSend transactional API provider
            'mailersend' => \App\Modules\Email\Mailersend\Mailersend::class,
        ];
    }

    /**
     * Aktif provider'ı ayarlar
     */
    public function setActiveProvider(?string $providerName = null)
    {
        if ($providerName === null) {
            // Tablo yoksa default smtp kullan
            if (!\Schema::hasTable('settings')) {
                $this->activeProvider = 'smtp';
                return;
            }
            $this->activeProvider = Setting::where('key', 'mail_provider')->value('value') ?? 'smtp';
        } else {
            $this->activeProvider = $providerName;

            // Tablo varsa aktif provider'ı veritabanına kaydet
            if (!\Schema::hasTable('settings')) {
                return;
            }

            // Aktif provider'ı veritabanına kaydet
            Setting::updateOrCreate(
                ['key' => 'mail_provider', 'group' => 'email'],
                ['value' => $providerName]
            );
        }

        // Aktif provider'ın ayarlarını genel mail konfigürasyonuna uygula
        $this->applyProviderConfigToLaravel();
    }

    /**
     * Aktif provider'ın ayarlarını Laravel'in genel mail konfigürasyonuna uygular
     */
    protected function applyProviderConfigToLaravel()
    {
        if (! $this->activeProvider || ! isset($this->providers[$this->activeProvider])) {
            return;
        }

        try {
            $providerInstance = $this->getActiveProviderInstance();

            // Provider'ın konfigürasyon metodunu çağır (varsa)
            if (method_exists($providerInstance, 'configureLaravelMail')) {
                $providerInstance->configureLaravelMail();
            }

            // Sistem ayarlarından global from address/name uygula
            $this->applyGlobalFromSettings();
        } catch (\Exception $e) {
            Log::error('Provider config uygulama hatası: '.$e->getMessage());
        }
    }

    /**
     * Sistem ayarlarından global from address/name'i Laravel mail config'ine uygular
     * system_emails_from_email ve system_emails_from_name ayarları varsa bunlar
     * Laravel'in mail.from konfigürasyonunu override eder
     */
    protected function applyGlobalFromSettings(): void
    {
        try {
            $fromEmail = Setting::where('key', 'system_emails_from_email')->value('value');
            $fromName = Setting::where('key', 'system_emails_from_name')->value('value');

            if (!empty($fromEmail)) {
                Config::set('mail.from.address', $fromEmail);
            }
            if (!empty($fromName)) {
                Config::set('mail.from.name', $fromName);
            }
        } catch (\Throwable $e) {
            Log::warning('Global from settings uygulanamadı: '.$e->getMessage());
        }
    }

    /**
     * Aktif provider instance'ını döndürür
     */
    protected function getActiveProviderInstance()
    {
        if (! $this->activeProvider || ! isset($this->providers[$this->activeProvider])) {
            throw new \Exception(__('email.active_provider_not_found', ['provider' => $this->activeProvider]));
        }

        $className = $this->providers[$this->activeProvider];
        $config = $this->getProviderConfig($this->activeProvider);

        return new $className($config);
    }

    /**
     * Provider konfigürasyonunu alır.
     *
     * PRC-623 / PRC-400 — tek kaynak `module_settings`: Module.config
     * accessor'ı decrypt edilmiş flat `[field_key => value]` array döner
     * (key'ler module getConfigFields() field key'leriyle birebir).
     */
    public function getProviderConfig(string $providerName): array
    {
        if (! \Schema::hasTable('modules')) {
            return [];
        }

        // PRC-654 — anahtarlar modül dosyasından (getConfigFields), value'lar
        // module_settings'ten merge edilir; modüle yeni field eklemek anında yansır.
        return \App\Helpers\ModuleConfig::resolved('email', $providerName, $this->getConfigFields($providerName));
    }

    /**
     * Email gönderir
     */
    public function sendEmail(array $params)
    {
        try {
            $provider = $this->getActiveProviderInstance();

            $result = $provider->sendEmail($params);
            $result['provider'] = $this->activeProvider;

            return $result;
        } catch (\Exception $e) {
            Log::error('Email gönderme hatası: '.$e->getMessage());

            return [
                'success' => false,
                'error' => $e->getMessage(),
                'provider' => $this->activeProvider,
            ];
        }
    }

    /**
     * Email template'i render eder
     */
    public function renderTemplate(array $params)
    {
        try {
            $provider = $this->getActiveProviderInstance();

            return $provider->renderTemplate($params);
        } catch (\Exception $e) {
            Log::error('Template render hatası: '.$e->getMessage());

            return [
                'success' => false,
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * Provider bağlantısını test eder
     */
    public function testProviderConnection(string $providerName, array $config = [])
    {
        try {
            if (! isset($this->providers[$providerName])) {
                throw new \Exception("Provider bulunamadı: {$providerName}");
            }

            $className = $this->providers[$providerName];
            $provider = new $className($config);

            return $provider->testConnection([]);
        } catch (\Exception $e) {
            Log::error('Provider test hatası: '.$e->getMessage());

            return [
                'success' => false,
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * Mevcut provider'ları listeler
     */
    public function getAvailableProviders(): array
    {
        $providers = [];

        foreach ($this->providers as $name => $className) {
            try {
                $instance = new $className([]);
                $providers[$name] = $instance->getModuleInfo();
            } catch (\Exception $e) {
                Log::error("Provider yükleme hatası {$name}: ".$e->getMessage());
            }
        }

        return $providers;
    }

    /**
     * Aktif provider'ı döndürür
     */
    public function getActiveProvider(): ?string
    {
        return $this->activeProvider;
    }

    /**
     * Provider'ın özelliklerini döndürür
     */
    public function getProviderFeatures(string $providerName): array
    {
        if (! isset($this->providers[$providerName])) {
            return [];
        }

        try {
            $className = $this->providers[$providerName];
            $instance = new $className([]);

            return $instance->getFeatures();
        } catch (\Exception $e) {
            return [];
        }
    }

    /**
     * Provider'ın konfigürasyon alanlarını döndürür
     */
    public function getProviderConfigFields(string $providerName): array
    {
        if (! isset($this->providers[$providerName])) {
            return [];
        }

        try {
            $className = $this->providers[$providerName];
            $instance = new $className([]);

            return $instance->getConfigFields();
        } catch (\Exception $e) {
            return [];
        }
    }

    /**
     * Provider'ı doğrular
     */
    public function validateProvider(string $providerName, array $config): array
    {
        if (! isset($this->providers[$providerName])) {
            return [
                'valid' => false,
                'errors' => ["Provider bulunamadı: {$providerName}"],
            ];
        }

        try {
            $className = $this->providers[$providerName];
            $instance = new $className($config);

            return $instance->validateConfig();
        } catch (\Exception $e) {
            return [
                'valid' => false,
                'errors' => [$e->getMessage()],
            ];
        }
    }

    /**
     * Email gönderimini devre dışı bırakıp bırakmadığını kontrol eder
     */
    public function isEmailSendingDisabled(): bool
    {
        return Setting::where('key', 'disable_email_sending')->value('value') === '1';
    }

    /**
     * Email gönderimini kontrol eder ve gerekirse devre dışı bırakır
     */
    protected function checkEmailSendingStatus()
    {
        if ($this->isEmailSendingDisabled()) {
            throw new \Exception('Email gönderimi devre dışı bırakılmış');
        }
    }

    // ─── ManageableModuleManager (PRC-327) ──────────────────────────────

    public function discover(): array
    {
        $out = [];
        foreach ($this->providers as $name => $class) {
            try {
                $instance = new $class([]);
                $info = method_exists($instance, 'getModuleInfo') ? $instance->getModuleInfo() : [];
                $out[] = [
                    'name' => $name,
                    'label' => $info['label'] ?? $info['name'] ?? strtoupper($name),
                ];
            } catch (\Throwable $e) {
                Log::warning("[EmailManager::discover] {$name}: {$e->getMessage()}");
            }
        }

        return $out;
    }

    public function getConfigFields(string $name): array
    {
        $legacy = $this->getProviderConfigFields($name);

        return ConfigFieldNormalizer::normalize($legacy);
    }

    public function test(string $name, array $config): TestResult
    {
        $result = $this->testProviderConnection($name, $config);
        $success = (bool) ($result['success'] ?? false);
        $message = (string) ($result['message'] ?? $result['error'] ?? ($success ? 'OK' : 'failed'));

        return new TestResult($success, $message, is_array($result) ? $result : []);
    }
}
