<?php

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedNamespaceFound -- APD is the established namespace shared with the Pro add-on and retained for backward compatibility.
namespace APD\Support;

use APD\Admin\AdminSettings;
use APD\Operations\OperationalMonitor;

defined('ABSPATH') || exit;

class ProductionReadiness
{
    public function evaluate() : array
    {
        $checks = [];
        $settings = (new AdminSettings())->all();
        $runtimeService = new CommercialRuntimeConfig();
        $runtime = $runtimeService->build($settings);
        $license = is_array($runtime['license'] ?? null) ? $runtime['license'] : [];
        $host = strtolower((string) wp_parse_url(home_url(), PHP_URL_HOST));
        $local = $this->isLocalHost($host);
        $environment = function_exists('wp_get_environment_type') ? wp_get_environment_type() : 'production';

        $this->add(
            $checks,
            'wordpress.version',
            version_compare(get_bloginfo('version'), '6.6', '>=') ? 'pass' : 'fail',
            __('WordPress version', 'asuka-product-designer'),
            sprintf(
                /* translators: %s is the installed WordPress version. */
                __('WordPress %s is installed; version 6.6 or newer is required.', 'asuka-product-designer'),
                get_bloginfo('version')
            )
        );
        $this->add(
            $checks,
            'php.version',
            version_compare(PHP_VERSION, '8.1', '>=') ? 'pass' : 'fail',
            __('PHP version', 'asuka-product-designer'),
            sprintf(
                /* translators: %s is the installed PHP version. */
                __('PHP %s is installed; version 8.1 or newer is required.', 'asuka-product-designer'),
                PHP_VERSION
            )
        );

        $this->add(
            $checks,
            'wordpress.environment',
            $environment === 'production' || $local ? ($local ? 'warning' : 'pass') : 'warning',
            __('WordPress environment', 'asuka-product-designer'),
            $local
                ? __('This is a local environment. Repeat the preflight on staging and production.', 'asuka-product-designer')
                : sprintf(
                    /* translators: %s is the WordPress environment type. */
                    __('WordPress reports the environment as %s.', 'asuka-product-designer'),
                    $environment
                )
        );

        $httpsReady = is_ssl() && strtolower((string) wp_parse_url(home_url(), PHP_URL_SCHEME)) === 'https';
        $this->add(
            $checks,
            'wordpress.https',
            $httpsReady ? 'pass' : ($local ? 'warning' : 'fail'),
            __('HTTPS', 'asuka-product-designer'),
            $httpsReady
                ? __('The WordPress home URL and current request use HTTPS.', 'asuka-product-designer')
                : ($local
                    ? __('HTTP is accepted locally, but staging and production must use HTTPS.', 'asuka-product-designer')
                    : __('The public WordPress site must use HTTPS.', 'asuka-product-designer'))
        );

        $debugEnabled = (defined('WP_DEBUG') && WP_DEBUG)
            || (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG)
            || (defined('WP_DEBUG_DISPLAY') && WP_DEBUG_DISPLAY);
        $this->add(
            $checks,
            'wordpress.debug',
            ! $debugEnabled ? 'pass' : ($local ? 'warning' : 'fail'),
            __('Debug output', 'asuka-product-designer'),
            ! $debugEnabled
                ? __('WordPress and script debug output are disabled.', 'asuka-product-designer')
                : __('Disable WP_DEBUG, SCRIPT_DEBUG, and WP_DEBUG_DISPLAY before production.', 'asuka-product-designer')
        );

        $fileEditorDisabled = defined('DISALLOW_FILE_EDIT') && DISALLOW_FILE_EDIT;
        $this->add(
            $checks,
            'wordpress.file_editor',
            $fileEditorDisabled ? 'pass' : 'warning',
            __('Dashboard file editor', 'asuka-product-designer'),
            $fileEditorDisabled
                ? __('DISALLOW_FILE_EDIT is enabled.', 'asuka-product-designer')
                : __('Define DISALLOW_FILE_EDIT as true in production to reduce administrative attack surface.', 'asuka-product-designer')
        );

        $woocommerceReady = class_exists('WooCommerce')
            && defined('WC_VERSION')
            && version_compare((string) WC_VERSION, '8.3', '>=');
        $this->add(
            $checks,
            'woocommerce.runtime',
            $woocommerceReady ? 'pass' : 'fail',
            __('WooCommerce runtime', 'asuka-product-designer'),
            $woocommerceReady
                ? sprintf(
                    /* translators: %s is the WooCommerce version. */
                    __('WooCommerce %s is active.', 'asuka-product-designer'),
                    (string) WC_VERSION
                )
                : __('WooCommerce 8.3 or newer must be active for commerce workflows.', 'asuka-product-designer')
        );

        $apiUrl = $runtimeService->apiBaseUrl();
        $apiReady = $apiUrl === CommercialRuntimeConfig::DEFAULT_API_BASE_URL;
        $this->add(
            $checks,
            'licensing.api',
            $apiReady ? 'pass' : 'fail',
            __('Symfony API', 'asuka-product-designer'),
            $apiReady
                ? __('The commercial API is locked to the official HTTPS endpoint.', 'asuka-product-designer')
                : __('The official commercial API endpoint is unavailable.', 'asuka-product-designer')
        );

        $licenseConfigured = ! empty($license['configured']);
        $tokenResolved = is_string($license['token'] ?? null) && trim((string) $license['token']) !== '';
        $licenseStatus = $this->commercialLicenseStatus($licenseConfigured, $tokenResolved, $local);
        $this->add(
            $checks,
            'licensing.token',
            $licenseStatus,
            __('Commercial license', 'asuka-product-designer'),
            ! $licenseConfigured
                ? __('No commercial license is configured. The designer runs in its supported free mode and premium modules remain unavailable.', 'asuka-product-designer')
                : ($tokenResolved
                    ? __('The server resolved an active signed runtime token without exposing the raw key.', 'asuka-product-designer')
                    : ($local
                        ? __('The configured license did not resolve locally. Premium modules remain unavailable until the Symfony API can validate it.', 'asuka-product-designer')
                        : __('The configured license could not be validated by the Symfony API.', 'asuka-product-designer')))
        );

        $runtimeAssetsReady = DesignerAssets::exists(DesignerAssets::coreFile())
            && DesignerAssets::exists(DesignerAssets::entrypoint('fabric'))
            && DesignerAssets::exists(DesignerAssets::entrypoint('babylon'));
        $this->add(
            $checks,
            'runtime.assets',
            $runtimeAssetsReady ? 'pass' : 'fail',
            __('Designer bundles', 'asuka-product-designer'),
            $runtimeAssetsReady
                ? __('Core, Fabric, and Babylon bundles are present and manifest-backed.', 'asuka-product-designer')
                : __('One or more required AsukaDesigner bundles are missing.', 'asuka-product-designer')
        );

        $heartbeatScheduled = wp_next_scheduled(OperationalMonitor::HEARTBEAT_HOOK) !== false;
        $lastHeartbeat = OperationalMonitor::lastHeartbeat();
        $heartbeatAge = $lastHeartbeat > 0 ? time() - $lastHeartbeat : PHP_INT_MAX;
        $cronStatus = $heartbeatScheduled && $heartbeatAge <= 20 * MINUTE_IN_SECONDS
            ? 'pass'
            : ($lastHeartbeat === 0 ? 'warning' : 'fail');
        $cronDetail = $lastHeartbeat > 0
            ? sprintf(
                /* translators: %s is a human-readable time difference. */
                __('The operational heartbeat last ran %s ago.', 'asuka-product-designer'),
                human_time_diff($lastHeartbeat, time())
            )
            : __('The operational heartbeat has not run yet. Trigger WP-Cron, then refresh this report.', 'asuka-product-designer');
        if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
            $cronDetail .= ' ' . __('DISABLE_WP_CRON is enabled, so a real server scheduler must call wp-cron.php.', 'asuka-product-designer');
        }
        $this->add($checks, 'operations.cron', $cronStatus, __('Scheduled operations', 'asuka-product-designer'), $cronDetail);

        $mailTransportDetected = $this->mailTransportDetected();
        $this->add(
            $checks,
            'operations.mail',
            $mailTransportDetected ? 'pass' : 'warning',
            __('Email transport', 'asuka-product-designer'),
            $mailTransportDetected
                ? __('A known SMTP/transactional mail integration is active.', 'asuka-product-designer')
                : __('WordPress exposes wp_mail(), but no known transport can be verified automatically. Send real inbox tests before launch.', 'asuka-product-designer')
        );

        $uploads = wp_upload_dir(null, false);
        $uploadsReady = empty($uploads['error'])
            && is_string($uploads['basedir'] ?? null)
            && is_dir((string) $uploads['basedir'])
            && wp_is_writable((string) $uploads['basedir']);
        $this->add(
            $checks,
            'filesystem.uploads',
            $uploadsReady ? 'pass' : 'fail',
            __('Media uploads', 'asuka-product-designer'),
            $uploadsReady
                ? __('The WordPress uploads directory is writable.', 'asuka-product-designer')
                : __('The WordPress uploads directory is unavailable or not writable.', 'asuka-product-designer')
        );

        $permalinksReady = trim((string) get_option('permalink_structure', '')) !== '';
        $this->add(
            $checks,
            'wordpress.permalinks',
            $permalinksReady ? 'pass' : 'warning',
            __('Permalinks', 'asuka-product-designer'),
            $permalinksReady
                ? __('Pretty permalinks are enabled.', 'asuka-product-designer')
                : __('Enable a non-plain permalink structure before public launch.', 'asuka-product-designer')
        );

        $privacyPageId = (int) get_option('wp_page_for_privacy_policy', 0);
        $privacyReady = $privacyPageId > 0 && get_post_status($privacyPageId) === 'publish';
        $this->add(
            $checks,
            'legal.privacy',
            $privacyReady ? 'pass' : 'warning',
            __('Privacy policy', 'asuka-product-designer'),
            $privacyReady
                ? __('A published WordPress privacy-policy page is configured.', 'asuka-product-designer')
                : __('Publish and assign a privacy policy covering uploads, saved designs, analytics, licensing, demos, and newsletters.', 'asuka-product-designer')
        );

        $manifestPath = ASUKA_PRODUCT_DESIGNER_PATH . 'RELEASE_MANIFEST.json';
        $checksumsPath = ASUKA_PRODUCT_DESIGNER_PATH . 'SHA256SUMS';
        $releaseMetadataReady = is_readable($manifestPath) && is_readable($checksumsPath);
        $this->add(
            $checks,
            'release.metadata',
            $releaseMetadataReady ? 'pass' : ($local ? 'warning' : 'fail'),
            __('Release metadata', 'asuka-product-designer'),
            $releaseMetadataReady
                ? __('The installed plugin contains its release manifest and file checksums.', 'asuka-product-designer')
                : __('Install the generated release ZIP rather than deploying the development workspace directly.', 'asuka-product-designer')
        );

        $summary = ['passed' => 0, 'warnings' => 0, 'failed' => 0, 'total' => count($checks)];
        foreach ($checks as $check) {
            if ($check['status'] === 'pass') {
                $summary['passed'] += 1;
            } elseif ($check['status'] === 'warning') {
                $summary['warnings'] += 1;
            } else {
                $summary['failed'] += 1;
            }
        }

        return [
            'ready' => $summary['failed'] === 0,
            'summary' => $summary,
            'checks' => $checks,
        ];
    }

    protected function add(array &$checks, string $id, string $status, string $label, string $detail) : void
    {
        $checks[] = compact('id', 'status', 'label', 'detail');
    }

    protected function isLocalHost(string $host) : bool
    {
        $host = strtolower(trim($host, '[]'));
        return in_array($host, ['localhost', '127.0.0.1', '::1'], true)
            || str_ends_with($host, '.test')
            || str_ends_with($host, '.local');
    }

    protected function commercialLicenseStatus(bool $configured, bool $resolved, bool $local) : string
    {
        if (! $configured || $resolved) {
            return 'pass';
        }

        return $local ? 'warning' : 'fail';
    }

    protected function mailTransportDetected() : bool
    {
        $detected = defined('WPMS_PLUGIN_VER')
            || defined('POST_SMTP_VER')
            || defined('FLUENTMAIL_PLUGIN_VERSION')
            || defined('WP_MAIL_SMTP_VERSION')
            || class_exists('WPMailSMTP\Core')
            || class_exists('PostmanSmtpController')
            || class_exists('FluentMail\App\Hooks\Handlers\SchedulerHandler');

        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- The apd_ hook is a documented integration API retained for backward compatibility.
        return (bool) apply_filters('apd_mail_transport_configured', $detected);
    }
}
