<?php

namespace AIPT\Core;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use WP_Error;
use AIPT\Core\CreditSystem\CreditManager;
use AIPT\Core\CreditSystem\CreditCache;

class FsManager {
    private static $instance = null;
    private $fs;
    private const PLAN_STATE_TRANSIENT = 'aipt_current_plan_state';
    private const TRIGGER_PLAN_CHANGE_EVENT_TRANSIENT = 'aipt_trigger_plan_changed_event';

    /**
     * Transient key for dismissing the SDK conflict notice.
     * Stored per-version so notice reappears after plugin updates.
     */
    private const SDK_CONFLICT_DISMISS_TRANSIENT = 'aipt_sdk_conflict_dismissed';

    /**
     * Cached SDK conflict detection result for this request.
     *
     * @var array|null
     */
    private $sdk_conflict_info = null;

    private function __construct() {
        $this->fs = aipt_fs();

        if (is_admin()) {
            add_action('wp_loaded', [$this, 'checkPlanChange']);
        }

        $this->setupFreemiusHooks();

        if (false === get_transient(self::PLAN_STATE_TRANSIENT)) {
            $this->savePlanState();
        }

        add_action('admin_print_footer_scripts', [$this, 'dispatch_plan_changed_event_script']);

        add_action('admin_notices', [$this, 'maybeShowSdkConflictNotice']);
        add_action('wp_ajax_aipt_dismiss_sdk_conflict', [$this, 'handleDismissSdkConflict']);
    }

    public static function getInstance(): self {
        if (self::$instance === null) {

            self::$instance = new self();
        } else {

        }
        return self::$instance;
    }

    /**
     * Freemius olay dinleyicilerini ayarlar
     */
    private function setupFreemiusHooks(): void {

        add_action('fs_after_license_change', [$this, 'handleLicenseChange'], 10, 2);

        add_action('fs_after_premium_version_activation', [$this, 'handleUpgrade']);

        add_action('fs_after_premium_version_deactivation', [$this, 'handleDowngrade']);
    }

    /**
     * Plan değişikliğinde yapılacak tüm işlemleri merkezi olarak yönetir.
     * Bu metod, Freemius hook'larından veya periyodik kontrolden çağrılmalıdır.
     *
     * @return array|WP_Error İşlem sonucu veya hata
     */
    private function processDetectedPlanChange() {
        try {

            $notify_result = $this->notifyPlanChangeToAPI();

            if (is_wp_error($notify_result)) {
                return $notify_result;
            }

            $creditManager = CreditManager::getInstance();

            $creditManager->getBalance(true);
            $creditManager->getCosts(true);

            delete_transient(self::PLAN_STATE_TRANSIENT);
            $this->savePlanState();

            set_transient(self::TRIGGER_PLAN_CHANGE_EVENT_TRANSIENT, true, MINUTE_IN_SECONDS);

            return [
                'success' => true,
                'message' => 'Plan change processed, API notified, and local data refreshed successfully.'
            ];
        } catch (\Exception $e) {
            return new WP_Error('exception_in_process_plan_change', $e->getMessage());
        }
    }

    /**
     * Lisans değişimini işler
     *
     * @param array $old_license Eski lisans bilgileri
     * @param array $new_license Yeni lisans bilgileri
     */
    public function handleLicenseChange($old_license, $new_license): void {

        $this->processDetectedPlanChange();
    }

    /**
     * Premium versiyon aktivasyonunu işler
     */
    public function handleUpgrade(): void {

        $this->processDetectedPlanChange();
    }

    /**
     * Premium versiyon deaktivasyonunu işler (downgrade)
     */
    public function handleDowngrade(): void {

        $this->processDetectedPlanChange();

        do_action( 'aipt_license_downgrade' );
    }

    private function getCurrentPlanState(): array {
        return [
            'plan' => $this->getPlanType(),
            'is_registered' => $this->is_registered(),
            'license_id' => $this->getLicenseId()
        ];
    }

    private function savePlanState(): void {
        $plan_state = $this->getCurrentPlanState();
        $encrypted_data = $this->encrypt_plan_state_data($plan_state);
        set_transient(self::PLAN_STATE_TRANSIENT, $encrypted_data);

    }

    /**
     * Plan state verisini şifreler
     *
     * @param array $data Şifrelenecek plan state verisi
     * @return mixed Şifrelenmiş veri veya başarısızlık durumunda orijinal veri
     */
    private function encrypt_plan_state_data(array $data) {
        try {
            $encrypted = CreditCache::encryptData($data);

            if ($encrypted !== false) {
                return $encrypted;
            }

            $this->log_encryption_failure('encrypt_failed', 'encryptData returned false');
            return $data;
        } catch (\Exception $e) {

            $this->log_encryption_failure('encrypt_exception', $e->getMessage());
            return $data;
        }
    }

    /**
     * Plan state verisini çözer
     *
     * @param mixed $data Çözülecek veri
     * @return array Çözülmüş veri veya boş array
     */
    private function decrypt_plan_state_data($data): array {

        if (empty($data)) {
            return [];
        }

        if (is_string($data)) {
            try {
                $decrypted = CreditCache::decryptData($data);

                if ($decrypted !== false && is_array($decrypted)) {
                    return $decrypted;
                }

                return [];
            } catch (\Exception $e) {

                return [];
            }
        }

        if (is_array($data)) {
            return $data;
        }

        return [];
    }

    /**
     * Şifreleme başarısızlığını loglar
     *
     * @param string $event_type Olay tipi
     * @param string $error_message Hata mesajı (opsiyonel)
     */
    private function log_encryption_failure(string $event_type, string $error_message = ''): void {

        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log(sprintf(
                '[AIPT FsManager] Encryption event: %s%s',
                $event_type,
                $error_message ? " - {$error_message}" : ''
            ));
        }
    }

    public function checkPlanChange(): void {

        $oldStateEncrypted = get_transient(self::PLAN_STATE_TRANSIENT);
        $oldState = $this->decrypt_plan_state_data($oldStateEncrypted);
        $currentState = $this->getCurrentPlanState();
        

        if (empty($oldState)) {

            $this->savePlanState();
            return; 
        }

        if ($oldState['plan'] !== $currentState['plan'] ||
            $oldState['license_id'] !== $currentState['license_id']) {

            $is_downgrade = $this->isDowngrade($oldState['plan'], $currentState['plan']);

            $this->processDetectedPlanChange();

            if ($is_downgrade) {
                do_action( 'aipt_license_downgrade' );
            }
        } else {

        }
    }

    /**
     * Check if plan change is a downgrade.
     *
     * @param string $old_plan Old plan type.
     * @param string $new_plan New plan type.
     * @return bool True if this is a downgrade.
     */
    private function isDowngrade(string $old_plan, string $new_plan): bool {
        $plan_hierarchy = [
            'free'     => 0,
            'pro'      => 1,
            'business' => 2,
        ];

        $old_level = $plan_hierarchy[$old_plan] ?? 0;
        $new_level = $plan_hierarchy[$new_plan] ?? 0;

        return $new_level < $old_level;
    }

    /**
     * Plan değişikliğini API'ye bildirir
     *
     * @return array|WP_Error İşlem sonucu veya hata
     */
    public function notifyPlanChangeToAPI() {
        try {
            $currentPlan = $this->getPlanType();

            $apiClient = new CreditSystem\CreditApiClient();
            $updateResult = $apiClient->updatePlan($currentPlan);

			if (!empty($updateResult['success'])) {
				if (isset($updateResult['plan_name'])) {
					update_option('aipt_credit_plan_name', sanitize_text_field($updateResult['plan_name']), false);
				}

                return [
                    'success' => true,
                    'message' => 'Plan updated successfully',
                    'plan_updated' => $updateResult['plan_updated'] ?? false,
                    'plan_downgraded' => $updateResult['plan_downgraded'] ?? false
                ];
            }

            return new WP_Error('api_error', $updateResult['error'] ?? 'Failed to update plan');
        } catch (\Exception $e) {
            return new WP_Error('exception', $e->getMessage());
        }
    }

    /**
     * Kredi ve plan önbelleğini temizler
     */
    public function clearCreditsCache(): void {
        try {
            $cache = new CreditCache();
            $cache->clear();
        } catch (\Exception $e) {

        }
    }

    public function is_registered(): bool {
        return $this->fs && $this->fs->is_registered();
    }

    public function getPlanType(): string {
        if (!$this->is_registered()) {
            return 'free';
        }

        if ($this->fs->is_plan_or_trial('business')) {
            return 'business';
        }

        if ($this->fs->is_plan_or_trial('pro')) {
            return 'pro';
        }

        return 'free';
    }

    /**
     * Force sync license data from Freemius servers and return fresh plan type.
     * 
     * Use when plan_mismatch is detected - this ensures we have the latest
     * license data before retrying plan update to remote API.
     *
     * @return string Fresh plan type after sync (free|pro|business)
     */
    public function forceSyncFromFreemius(): string {
        if (!$this->fs || !$this->is_registered()) {
            return 'free';
        }

        try {

            $this->fs->sync_install([], true);
            

            delete_transient(self::PLAN_STATE_TRANSIENT);
            

            return $this->getPlanType();
        } catch (\Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
            }

            return $this->getPlanType();
        }
    }

    public function getSiteId(): string {
        if (!$this->is_registered()) {
            return '';
        }
        return (string)$this->fs->get_site()->id;
    }

    public function getPluginId(): string {
        if (!$this->fs) {
            return '';
        }
        return (string)$this->fs->get_id();
    }

    public function getLicenseId(): string {
        if (!$this->is_registered() || !$this->fs->has_active_valid_license()) {
            return '';
        }
        return (string)$this->fs->_get_license()->id;
    }

    /**
     * Freemius kullanıcı ID'sini getirir
     *
     * @return string Kullanıcı ID'si veya boş string
     */
    public function getUserId(): string {
        if (!$this->is_registered() || !$this->fs->is_registered()) {
            return '';
        }

        $user = $this->fs->get_user();
        return $user ? (string)$user->id : '';
    }

    /**
     * Cache'den plan ID'sini getirir
     *
     * @return string|null Plan ID'si veya null
     */
    public function getPlanId(): ?string {
        try {

            $creditManager = CreditManager::getInstance();
            $balance = $creditManager->getBalance();

            if (is_array($balance) && isset($balance['plan_id'])) {
                return (string) $balance['plan_id'];
            }

            return null;
        } catch (\Exception $e) {
            return null;
        }
    }

    public function hasBusinessFeature(): bool {
        return $this->is_registered() && $this->fs->is_plan_or_trial('business');
    }

    public function hasProFeature(): bool {
        return $this->is_registered() && ($this->fs->is_plan_or_trial('pro') || $this->fs->is_plan_or_trial('business'));
    }

    /**
     * Checks if user is using premium version files (not just Freemius plan)
     * This is different from hasProFeature() which only checks Freemius plan
     */
    public function isUsingPremiumFiles(): bool {
        return $this->fs && $this->fs->is_premium();
    }

    public function showUpgradeNotice(): void {
        if (!$this->is_registered() || !$this->fs->is_premium()) {
            $this->fs->add_sticky_admin_message(
                'This feature requires a premium license. Please upgrade to continue.',
                'upgrade_notice',
                'Update Required'
            );
        }
    }

    /**
     * Plan önbelleğini temizler
     */
    public function clearPlanCache(): void {
        delete_transient(self::PLAN_STATE_TRANSIENT);

        $this->savePlanState();
    }

    /**
     * Plan değişikliğinde yapılacak tüm işlemleri merkezi olarak yönetir.
     * Bu metod, Freemius hook'larından veya periyodik kontrolden çağrılmalıdır.
     *
     * @return array|WP_Error İşlem sonucu veya hata
     */
    public function handlePlanChange() {

        return $this->processDetectedPlanChange();
    }

    /**
     * Dispatches the aipt_plan_changed JavaScript event if the corresponding transient is set.
     * This is hooked to 'admin_print_footer_scripts'.
     */
    public function dispatch_plan_changed_event_script(): void {
        if (\get_transient(self::TRIGGER_PLAN_CHANGE_EVENT_TRANSIENT)) {
            $current_screen = \get_current_screen();
            $script_handle = null;

            if ($current_screen && strpos($current_screen->id, 'page_aipt-advanced-bulk-generator') !== false) {
                $script_handle = 'aipt-description-generator';
            }

            if ($script_handle) {
                $script = "
                    document.addEventListener('DOMContentLoaded', function() {

                        window.dispatchEvent(new CustomEvent('aipt_plan_changed'));
                    });
                ";
                \wp_add_inline_script($script_handle, $script);

                \delete_transient(self::TRIGGER_PLAN_CHANGE_EVENT_TRANSIENT);

            } else {
                \delete_transient(self::TRIGGER_PLAN_CHANGE_EVENT_TRANSIENT);
            }
        }
    }

    /**
     * Get the Freemius SDK version bundled with this plugin.
     *
     * Reads directly from the SDK's start.php to avoid hardcoding.
     * Result is statically cached — file is read at most once per request.
     *
     * @return string SDK version (e.g. '2.13.0') or empty string if unreadable.
     */
    private function getBundledSdkVersion(): string {
        static $version = null;

        if ($version !== null) {
            return $version;
        }

        $start_file = AIPT_PLUGIN_DIR . 'vendor/freemius/wordpress-sdk/start.php';

        if (!file_exists($start_file)) {
            $version = '';
            return $version;
        }

        $content = file_get_contents($start_file, false, null, 0, 500);

        if ($content && preg_match('/\$this_sdk_version\s*=\s*\'([^\']+)\'/', $content, $matches)) {
            $version = $matches[1];
        } else {
            $version = '';
        }

        return $version;
    }

    /**
     * Detect if another plugin's Freemius SDK is overriding ours.
     *
     * Freemius loads only the newest SDK globally. When a third-party plugin
     * bundles a development SDK (e.g. 999.99.99 from Composer dev-master),
     * it always wins `version_compare()` and can cause license detection
     * failures for plugins using stable SDK versions.
     *
     * @return array{has_conflict: bool, active_version: string, active_sdk_path: string, active_plugin_path: string, our_sdk_registered: bool}
     */
    public function detectSdkConflict(): array {

        if ($this->sdk_conflict_info !== null) {
            return $this->sdk_conflict_info;
        }

        $result = [
            'has_conflict'       => false,
            'active_version'     => $this->getBundledSdkVersion(),
            'active_sdk_path'    => '',
            'active_plugin_path' => '',
            'our_sdk_registered' => true,
        ];

        global $fs_active_plugins;

        $active_plugins = $fs_active_plugins;
        if (empty($active_plugins) || !is_object($active_plugins)) {
            $active_plugins = get_option('fs_active_plugins');
        }

        if (empty($active_plugins) || !is_object($active_plugins)) {
            $this->sdk_conflict_info = $result;
            return $result;
        }

        if (!empty($active_plugins->newest) && is_object($active_plugins->newest)) {
            $newest_version = $active_plugins->newest->version ?? '';
            $newest_sdk_path = $active_plugins->newest->sdk_path ?? '';

            $result['active_version']  = $newest_version;
            $result['active_sdk_path'] = $newest_sdk_path;

            if (
                !empty($newest_sdk_path) &&
                isset($active_plugins->plugins[$newest_sdk_path]) &&
                is_object($active_plugins->plugins[$newest_sdk_path])
            ) {
                $result['active_plugin_path'] = $active_plugins->plugins[$newest_sdk_path]->plugin_path ?? '';
            }

            $is_dev_version = version_compare($newest_version, '10.0.0', '>=');
            $is_different_plugin = (
                !empty($newest_sdk_path) &&
                strpos($newest_sdk_path, 'ai-product-tools') === false
            );

            if ($is_dev_version && $is_different_plugin) {
                $result['has_conflict'] = true;
            }
        }

        if (!empty($active_plugins->plugins) && is_array($active_plugins->plugins)) {
            $our_sdk_found = false;
            foreach ($active_plugins->plugins as $sdk_path => $data) {
                if (strpos($sdk_path, 'ai-product-tools') !== false) {
                    $our_sdk_found = true;
                    break;
                }
            }
            $result['our_sdk_registered'] = $our_sdk_found;
        }

        $this->sdk_conflict_info = $result;
        return $result;
    }

    /**
     * Show admin notice when an SDK conflict is detected.
     *
     * Only shown on plugin pages (WordPress.org Guideline 10/11 compliant)
     * and dismissible with a 30-day snooze.
     */
    public function maybeShowSdkConflictNotice(): void {

        if (!$this->isPluginAdminPage()) {
            return;
        }

        $dismissed = get_transient(self::SDK_CONFLICT_DISMISS_TRANSIENT);
        if ($dismissed) {
            return;
        }

        $conflict = $this->detectSdkConflict();
        if (!$conflict['has_conflict']) {
            return;
        }

        $is_affected = !$this->is_registered();
        if (!$is_affected) {

            return;
        }

        $conflicting_plugin = !empty($conflict['active_plugin_path'])
            ? '<code>' . esc_html(dirname($conflict['active_plugin_path'])) . '</code>'
            : esc_html__('another plugin', 'ai-product-tools');

        $sdk_version = esc_html($conflict['active_version']);

        printf(
            '<div class="notice notice-warning is-dismissible aipt-sdk-conflict-notice" data-nonce="%s">
                <p><strong>%s</strong></p>
                <p>%s</p>
                <p><small>%s</small></p>
            </div>',
            esc_attr(wp_create_nonce('aipt_dismiss_sdk_conflict')),
            esc_html__('AI Product Tools — Freemius SDK Conflict Detected', 'ai-product-tools'),
            sprintf(
                /* translators: 1: Conflicting plugin name, 2: SDK version number */
                esc_html__(
                    'A development version of the Freemius SDK (v%2$s) bundled by %1$s is overriding this plugin\'s license system. This may cause your plan to appear as "Free" even if you have an active license. Please contact the developer of %1$s and ask them to use a stable Freemius SDK version, or try temporarily deactivating that plugin to verify your license.',
                    'ai-product-tools'
                ),
                $conflicting_plugin,
                $sdk_version
            ),
            sprintf(
                /* translators: 1: SDK version string, 2: Freemius debug page link */
                esc_html__( 'Diagnostic: Active SDK v%1$s | See %2$s for details.', 'ai-product-tools' ),
                $sdk_version,
                '<a href="' . esc_url(\admin_url('admin.php?page=freemius')) . '">Freemius Debug</a>'
            )
        );

        $this->enqueueDismissScript();
    }

    /**
     * Enqueue the inline dismiss script for the SDK conflict notice.
     */
    private function enqueueDismissScript(): void {
        static $enqueued = false;
        if ($enqueued) {
            return;
        }
        $enqueued = true;

        add_action('admin_footer', function () {
            ?>
            <script>
            (function() {
                var notice = document.querySelector('.aipt-sdk-conflict-notice');
                if (!notice) return;
                notice.addEventListener('click', function(e) {
                    if (e.target.classList.contains('notice-dismiss') || e.target.closest('.notice-dismiss')) {
                        var xhr = new XMLHttpRequest();
                        xhr.open('POST', ajaxurl);
                        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                        xhr.send('action=aipt_dismiss_sdk_conflict&nonce=' + notice.dataset.nonce);
                    }
                });
            })();
            </script>
            <?php
        });
    }

    /**
     * AJAX handler for dismissing the SDK conflict notice.
     * Sets a 30-day transient so the notice doesn't reappear immediately.
     */
    public function handleDismissSdkConflict(): void {
        check_ajax_referer('aipt_dismiss_sdk_conflict', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_die(-1);
        }

        set_transient(self::SDK_CONFLICT_DISMISS_TRANSIENT, '1', 30 * DAY_IN_SECONDS);
        wp_die('1');
    }

    /**
     * Check if the current admin page belongs to this plugin.
     *
     * @return bool
     */
    private function isPluginAdminPage(): bool {
        if (!is_admin()) {
            return false;
        }

        $page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';

        if (empty($page)) {
            return false;
        }

        if ('ai-product-tools' === $page) {
            return true;
        }

        return strpos($page, 'aipt-') === 0 || strpos($page, 'ai-product-tools-') === 0;
    }
}
