<?php
if (!defined('ABSPATH')) { exit; }

final class PTMS_Updater {
    private const METADATA_URL = 'https://trust.ibmw.com.tr/api/update-metadata.php';
    private const PACKAGE_PLACEHOLDER = 'https://trust.ibmw.com.tr/api/update-download.php?product=pw-merchant';

    private static $instance = null;

    public static function instance() {
        if (self::$instance === null) { self::$instance = new self(); }
        return self::$instance;
    }

    private function __construct() {
        add_filter('pre_set_site_transient_update_plugins', array($this, 'check'));
        add_filter('plugins_api', array($this, 'info'), 20, 3);
        add_filter('upgrader_pre_download', array($this, 'pre_download'), 10, 4);
        add_action('upgrader_process_complete', array($this, 'clear'), 10, 2);
        add_action('admin_post_ptms_update_refresh', array($this, 'manual_refresh'));
    }

    public function check($transient) {
        if (!is_object($transient)) { $transient = new stdClass(); }
        $plugin = plugin_basename(PTMS_FILE);

        if (empty($transient->checked) || !isset($transient->checked[$plugin])) {
            return $transient;
        }

        $update = $this->metadata(false);
        if (
            is_array($update)
            && !empty($update['version'])
            && version_compare(PTMS_VERSION, (string) $update['version'], '<')
        ) {
            $transient->response[$plugin] = (object) array(
                'id' => 'ptms-' . sanitize_text_field((string) $update['version']),
                'slug' => 'pw-merchant-api-system',
                'plugin' => $plugin,
                'new_version' => (string) $update['version'],
                'url' => (string) ($update['url'] ?? ''),
                // WordPress standart "Şimdi güncelle" bağlantısını gösterir.
                // Gerçek tek kullanımlık paket adresi indirme anında alınır.
                'package' => self::PACKAGE_PLACEHOLDER,
                'requires' => (string) ($update['requires'] ?? ''),
                'requires_php' => (string) ($update['requires_php'] ?? ''),
                'tested' => (string) ($update['tested'] ?? ''),
            );
            unset($transient->no_update[$plugin]);
        } else {
            unset($transient->response[$plugin]);
            if (is_array($update) && !empty($update['version'])) {
                $transient->no_update[$plugin] = (object) array(
                    'id' => 'ptms-' . sanitize_text_field((string) $update['version']),
                    'slug' => 'pw-merchant-api-system',
                    'plugin' => $plugin,
                    'new_version' => (string) $update['version'],
                    'url' => (string) ($update['url'] ?? ''),
                    'package' => self::PACKAGE_PLACEHOLDER,
                    'requires' => (string) ($update['requires'] ?? ''),
                    'requires_php' => (string) ($update['requires_php'] ?? ''),
                    'tested' => (string) ($update['tested'] ?? ''),
                );
            }
        }

        return $transient;
    }

    public function info($result, $action, $args) {
        if (
            $action !== 'plugin_information'
            || empty($args->slug)
            || $args->slug !== 'pw-merchant-api-system'
        ) {
            return $result;
        }

        $update = $this->metadata(false);
        if (!is_array($update) || empty($update['version'])) {
            return $result;
        }

        return (object) array(
            'name' => (string) ($update['name'] ?? 'PW Feed'),
            'slug' => 'pw-merchant-api-system',
            'version' => (string) $update['version'],
            'author' => 'PW Feed',
            'homepage' => (string) ($update['url'] ?? ''),
            'requires' => (string) ($update['requires'] ?? ''),
            'requires_php' => (string) ($update['requires_php'] ?? ''),
            'tested' => (string) ($update['tested'] ?? ''),
            'download_link' => self::PACKAGE_PLACEHOLDER,
            'sections' => is_array($update['sections'] ?? null)
                ? $update['sections']
                : array(),
        );
    }

    /**
     * WordPress gerçek indirmeye başlamadan hemen önce taze, tek kullanımlık
     * Trust2 indirme bileti alır. Böylece güncelleme transiyentindeki eski
     * 120 saniyelik URL yüzünden güncelleme bozulmaz.
     *
     * @return mixed
     */
    public function pre_download($reply, $package, $upgrader, $hook_extra) {
        if (is_wp_error($reply)) { return $reply; }

        $plugin = isset($hook_extra['plugin'])
            ? (string) $hook_extra['plugin']
            : '';

        if ($plugin !== plugin_basename(PTMS_FILE)) {
            return $reply;
        }

        $fresh = $this->download_ticket();
        if (
            !is_array($fresh)
            || empty($fresh['package'])
            || empty($fresh['version'])
            || !version_compare(PTMS_VERSION, (string) $fresh['version'], '<')
        ) {
            return new WP_Error(
                'ptms_update_ticket_unavailable',
                __('Could not obtain a secure download link for the update package. Please try again soon.', 'pw-merchant-api-system')
            );
        }

        $url = esc_url_raw((string) $fresh['package']);
        if (
            $url === ''
            || strpos($url, 'https://trust.ibmw.com.tr/download-v2.php?token=') !== 0
        ) {
            return new WP_Error(
                'ptms_update_package_invalid',
                __('The secure download address for the update package could not be verified.', 'pw-merchant-api-system')
            );
        }

        $timeout = 300;
        $tmp = download_url($url, $timeout);

        if (is_wp_error($tmp)) {
            return new WP_Error(
                'ptms_update_download_failed',
                __('Failed to download update package:', 'pw-merchant-api-system') . $tmp->get_error_message()
            );
        }

        $validated = $this->validate_package($tmp, $fresh);
        if (is_wp_error($validated)) {
            @unlink($tmp);
            return $validated;
        }

        return $tmp;
    }

    private function validate_package($path, array $metadata) {
        $expected_hash = strtolower(trim((string)($metadata['sha256'] ?? '')));
        if (!preg_match('/^[a-f0-9]{64}$/', $expected_hash)) {
            return new WP_Error('ptms_update_hash_missing', __('The update package integrity value is missing.', 'pw-merchant-api-system'));
        }
        $actual_hash = hash_file('sha256', $path);
        if (!is_string($actual_hash) || !hash_equals($expected_hash, strtolower($actual_hash))) {
            return new WP_Error('ptms_update_hash_mismatch', __('The update package integrity check failed.', 'pw-merchant-api-system'));
        }
        if (!class_exists('ZipArchive')) {
            return new WP_Error('ptms_update_zip_validation_unavailable', __('The update package cannot be securely inspected because PHP ZipArchive is unavailable.', 'pw-merchant-api-system'));
        }

        $expected_root = trim((string)($metadata['root_directory'] ?? 'pw-merchant-api-system'), '/');
        $expected_version = trim((string)($metadata['version'] ?? ''));
        $zip = new ZipArchive();
        if ($zip->open($path) !== true) {
            return new WP_Error('ptms_update_zip_invalid', __('The update package is not a valid ZIP archive.', 'pw-merchant-api-system'));
        }
        try {
            for ($i = 0; $i < $zip->numFiles; $i++) {
                $name = (string)$zip->getNameIndex($i);
                $normalized = str_replace('\\', '/', $name);
                if ($normalized === '' || strpos($normalized, '/') === 0 || preg_match('#(^|/)\.\.(/|$)#', $normalized)) {
                    return new WP_Error('ptms_update_zip_path_invalid', __('The update package contains an unsafe file path.', 'pw-merchant-api-system'));
                }
                if ($normalized !== $expected_root && strpos($normalized, $expected_root . '/') !== 0) {
                    return new WP_Error('ptms_update_root_mismatch', __('The update package root directory does not match PW Feed.', 'pw-merchant-api-system'));
                }
            }

            $plugin_file = $expected_root . '/pw-merchant-api-system.php';
            $plugin_source = $zip->getFromName($plugin_file);
            if (!is_string($plugin_source)) {
                return new WP_Error('ptms_update_plugin_file_missing', __('The PW Feed main plugin file is missing from the update package.', 'pw-merchant-api-system'));
            }
            if (!preg_match('/^[ \t\/*#@]*Version:\s*([0-9A-Za-z.\-+]+)/mi', $plugin_source, $match)
                || (string)$match[1] !== $expected_version) {
                return new WP_Error('ptms_update_version_mismatch', __('The version inside the update package does not match the announced version.', 'pw-merchant-api-system'));
            }
            if (!preg_match("/define\\(\\s*'PTMS_TRUST_PRODUCT_KEY'\\s*,\\s*'pw-merchant'\\s*\\)/", $plugin_source)) {
                return new WP_Error('ptms_update_product_mismatch', __('The update package does not belong to the expected PW Feed product.', 'pw-merchant-api-system'));
            }
            $manifest_source = $zip->getFromName($expected_root . '/ptms-manifest.json');
            $manifest = is_string($manifest_source) ? json_decode($manifest_source, true) : null;
            if (!is_array($manifest) || (string)($manifest['version'] ?? '') !== $expected_version) {
                return new WP_Error('ptms_update_manifest_invalid', __('The update package manifest could not be verified.', 'pw-merchant-api-system'));
            }
        } finally {
            $zip->close();
        }
        return true;
    }

    public function clear($upgrader, $options) {
        if (
            ($options['action'] ?? '') === 'update'
            && ($options['type'] ?? '') === 'plugin'
        ) {
            delete_transient('ptms_update_metadata_v3');
            delete_site_transient('update_plugins');
        }
    }

    public function manual_refresh() {
        if (!current_user_can('update_plugins')) {
            wp_die(__('Unauthorized transaction.', 'pw-merchant-api-system'));
        }
        check_admin_referer('ptms_update_refresh');

        delete_transient('ptms_update_metadata_v3');
        delete_site_transient('update_plugins');
        wp_update_plugins();

        wp_safe_redirect(admin_url('plugins.php?ptms_update_refreshed=1'));
        exit;
    }

    /**
     * @return array|null
     */
    private function metadata($force = false) {
        if (!$force) {
            $cached = get_transient('ptms_update_metadata_v3');
            if (is_array($cached)) {
                return !empty($cached) ? $cached : null;
            }
        }

        $response = wp_remote_post(self::METADATA_URL, array(
            'timeout' => 15,
            'redirection' => 0,
            'sslverify' => true,
            'headers' => array(
                'Content-Type' => 'application/json',
                'Accept' => 'application/json',
            ),
            'body' => wp_json_encode(array(
                'product_key' => PTMS_TRUST_PRODUCT_KEY,
                'current_version' => PTMS_VERSION,
            )),
        ));

        if (is_wp_error($response)) {
            if (!$force) {
                set_transient('ptms_update_metadata_v3', array(), 5 * MINUTE_IN_SECONDS);
            }
            return null;
        }

        $status = (int) wp_remote_retrieve_response_code($response);
        $result = json_decode((string) wp_remote_retrieve_body($response), true);
        if (
            $status !== 200
            || !is_array($result)
            || empty($result['ok'])
            || empty($result['update'])
            || !is_array($result['update'])
        ) {
            if (!$force) {
                set_transient('ptms_update_metadata_v3', array(), 5 * MINUTE_IN_SECONDS);
            }
            return null;
        }

        $update = $result['update'];
        if (
            (string)($update['slug'] ?? '') !== PTMS_TRUST_PRODUCT_KEY
            || !preg_match('/^[a-f0-9]{64}$/', strtolower((string)($update['sha256'] ?? '')))
            || (string)($update['root_directory'] ?? '') !== 'pw-merchant-api-system'
        ) {
            return null;
        }

        // Sürüm duyurusu lisans durumundan bağımsızdır. Böylece eklentinin
        // kurulu olduğu tüm siteler WordPress'in standart güncelleme uyarısını
        // görür. Paket indirme yetkisi ayrıca, indirme anında doğrulanır.
        if (!$force) {
            set_transient('ptms_update_metadata_v3', $update, 30 * MINUTE_IN_SECONDS);
        }

        return $update;
    }

    /**
     * Gerçek ZIP yalnız etkin Demo veya Pro yetkisi doğrulandıktan sonra
     * kısa ömürlü ve tek kullanımlık adresle indirilir.
     *
     * @return array|null
     */
    private function download_ticket() {
        if (!in_array(PTMS_License::status(), array('demo', 'pro'), true)) {
            return null;
        }

        $installation = trim((string) get_option('ptms_trust_installation_id', ''));
        if ($installation === '') {
            return null;
        }

        $result = PTMS_License::signed_request('update-check-v2.php', array(
            'installation_id' => $installation,
            'product_key' => PTMS_TRUST_PRODUCT_KEY,
            'current_version' => PTMS_VERSION,
        ));

        if (
            is_wp_error($result)
            || empty($result['eligible'])
            || empty($result['update'])
            || !is_array($result['update'])
        ) {
            return null;
        }

        $update = $result['update'];
        if (
            (string)($update['slug'] ?? '') !== PTMS_TRUST_PRODUCT_KEY
            || !preg_match('/^[a-f0-9]{64}$/', strtolower((string)($update['sha256'] ?? '')))
            || (string)($update['root_directory'] ?? '') !== 'pw-merchant-api-system'
        ) {
            return null;
        }

        return $update;
    }
}
