<?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;

defined('ABSPATH') || exit;

class CommercialRuntimeConfig
{
    public const DEFAULT_API_BASE_URL = 'https://api.asukadev.com';

    private const TOKEN_TRANSIENT_PREFIX = 'apd_license_token_';
    private const TOKEN_FAILURE_SENTINEL = '__apd_license_unavailable__';

    private const PLAN_ADDON_FEATURES = [
        'starter' => ['studiobasic', 'pricing'],
        'pro' => ['studiobasic', 'pricing', 'pricingrules', 'fixedslots', 'drawingareas', 'modeloptimization', 'assembly', 'productparameters'],
        'agency' => ['studiobasic', 'pricing', 'pricingrules', 'fixedslots', 'drawingareas', 'modeloptimization', 'assembly', 'productparameters'],
    ];

    public function build(?array $settings = null) : array
    {
        $settings = $settings ?? (new AdminSettings())->all();
        $baseUrl = $this->apiBaseUrl();
        $domain = $this->resolveDomain($settings);
        $instanceId = $this->resolveInstanceId();
        $licenseEnabled = (string) ($settings['license_enabled'] ?? '1') === '1';
        $licenseKey = trim((string) ($settings['license_key'] ?? ''));

        $license = [
            'enabled' => $licenseEnabled,
            'configured' => $licenseKey !== '',
            'domain' => $domain,
            'instanceId' => $instanceId,
            'channel' => 'wordpress',
            'audience' => 'asuka-designer',
        ];

        if ($licenseEnabled && $licenseKey !== '') {
            $token = $this->resolveLicenseToken($settings, $baseUrl, $domain, $instanceId);
            if ($token !== '') {
                $license['token'] = $token;
            }
        }

        $runtime = [
            'license' => $license,
            'ai' => [],
            'exports' => [],
        ];

        $runtime['ai'] = [
            'textToImage' => ['creditCost' => 1],
            'backgroundRemoval' => ['creditCost' => 1],
        ];
        $runtime['exports'] = [
            'consume' => ['creditCost' => 1],
            'serverHd' => [
                'creditCost' => 1,
                'autoDownload' => true,
            ],
        ];

        return $runtime;
    }

    public function apiBaseUrl() : string
    {
        return self::DEFAULT_API_BASE_URL;
    }

    public function licenseEntitlements(?array $settings = null) : array
    {
        $runtime = $this->build($settings);
        $license = is_array($runtime['license'] ?? null) ? $runtime['license'] : [];
        return $this->entitlementsFromLicense($license);
    }

    public function entitlementsFromLicense(array $license) : array
    {
        $payload = $this->decodeCompactToken((string) ($license['token'] ?? ''));
        if ($payload === [] || empty($payload['active'])) {
            return [
                'plan' => 'free',
                'features' => [],
                'payload' => [],
            ];
        }

        $plan = sanitize_key((string) ($payload['plan'] ?? 'free')) ?: 'free';
        $features = [];
        foreach (self::PLAN_ADDON_FEATURES[$plan] ?? [] as $feature) {
            $features[$feature] = true;
        }
        foreach ((array) ($payload['features'] ?? []) as $feature => $enabled) {
            $feature = sanitize_key((string) $feature);
            if ($feature !== '') {
                $features[$feature] = (bool) $enabled;
            }
        }

        return [
            'plan' => $plan,
            'features' => $features,
            'payload' => $payload,
        ];
    }

    private function resolveLicenseToken(array $settings, string $baseUrl, string $domain, string $instanceId) : string
    {
        $licenseKey = trim((string) ($settings['license_key'] ?? ''));
        if ($licenseKey === '' || ! function_exists('wp_remote_post')) {
            return '';
        }

        $cacheKey = self::TOKEN_TRANSIENT_PREFIX . md5($baseUrl . '|' . $licenseKey . '|' . $domain . '|' . $instanceId . '|' . ASUKA_PRODUCT_DESIGNER_VERSION);
        $cached = get_transient($cacheKey);
        if ($cached === self::TOKEN_FAILURE_SENTINEL) {
            return '';
        }
        if (is_string($cached) && trim($cached) !== '') {
            return trim($cached);
        }

        $body = [
            'key' => $licenseKey,
            'product' => 'asuka-designer',
            'audience' => 'asuka-designer',
            'channel' => 'wordpress',
            'domain' => $domain,
            'instanceId' => $instanceId,
            'version' => ASUKA_PRODUCT_DESIGNER_VERSION,
            'acceptCompactToken' => true,
        ];
        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- The apd_ hook is a documented integration API retained for backward compatibility.
        $timeout = (int) apply_filters('apd_license_http_timeout', 8, $baseUrl, $settings);
        $timeout = max(3, min(30, $timeout));

        $request = [
            'timeout' => $timeout,
            'redirection' => 2,
            'headers' => [
                'Content-Type' => 'application/json',
                'Accept' => 'application/json',
            ],
            'body' => wp_json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
        ];
        $response = wp_safe_remote_post($baseUrl . '/v1/licenses/resolve', $request);

        if (is_wp_error($response)) {
            $this->cacheTokenFailure($cacheKey);
            return '';
        }

        $status = (int) wp_remote_retrieve_response_code($response);
        if ($status < 200 || $status >= 300) {
            $this->cacheTokenFailure($cacheKey);
            return '';
        }

        $payload = json_decode((string) wp_remote_retrieve_body($response), true);
        if (! is_array($payload)) {
            $this->cacheTokenFailure($cacheKey);
            return '';
        }

        $token = '';
        if (isset($payload['token']) && is_string($payload['token'])) {
            $token = trim($payload['token']);
        } elseif (isset($payload['data']) && is_array($payload['data']) && isset($payload['data']['token']) && is_string($payload['data']['token'])) {
            $token = trim($payload['data']['token']);
        }

        if ($token !== '') {
            set_transient($cacheKey, $token, $this->tokenCacheTtl($token));
        } else {
            $this->cacheTokenFailure($cacheKey);
        }

        return $token;
    }

    private function resolveDomain(array $settings) : string
    {
        $configured = $this->normalizeDomain((string) ($settings['license_domain'] ?? ''));
        if ($configured !== '') {
            return $configured;
        }

        $host = wp_parse_url(home_url(), PHP_URL_HOST);
        return $this->normalizeDomain(is_string($host) ? $host : '');
    }

    private function decodeCompactToken(string $token) : array
    {
        $parts = explode('.', trim($token));
        if (count($parts) !== 3) {
            return [];
        }

        $encodedPayload = strtr($parts[1], '-_', '+/');
        $encodedPayload .= str_repeat('=', (4 - strlen($encodedPayload) % 4) % 4);
        $decodedPayload = base64_decode($encodedPayload, true);
        if (! is_string($decodedPayload) || $decodedPayload === '') {
            return [];
        }

        $payload = json_decode($decodedPayload, true);
        return is_array($payload) ? $payload : [];
    }

    private function tokenCacheTtl(string $token) : int
    {
        $payload = $this->decodeCompactToken($token);
        $expiresAt = trim((string) ($payload['expiresAt'] ?? ''));
        if ($expiresAt === '') {
            return 30 * MINUTE_IN_SECONDS;
        }

        $expires = strtotime($expiresAt);
        if (! is_int($expires) || $expires <= time()) {
            return MINUTE_IN_SECONDS;
        }

        return max(MINUTE_IN_SECONDS, min(30 * MINUTE_IN_SECONDS, $expires - time() - MINUTE_IN_SECONDS));
    }

    private function cacheTokenFailure(string $cacheKey) : void
    {
        set_transient($cacheKey, self::TOKEN_FAILURE_SENTINEL, MINUTE_IN_SECONDS);
    }

    private function normalizeDomain(string $domain) : string
    {
        $domain = strtolower(trim($domain));
        if ($domain === '') {
            return '';
        }

        if (str_contains($domain, '://')) {
            $host = wp_parse_url($domain, PHP_URL_HOST);
            $domain = is_string($host) ? $host : $domain;
        }

        $domain = preg_replace('/^www\./', '', $domain) ?? $domain;
        $domain = preg_replace('/:\d+$/', '', $domain) ?? $domain;
        $domain = trim($domain, " \t\n\r\0\x0B/");

        return $domain;
    }

    private function resolveInstanceId() : string
    {
        $stored = get_option('apd_license_instance_id', '');
        if (is_string($stored) && trim($stored) !== '') {
            return trim($stored);
        }

        $seed = home_url() . '|' . wp_salt('auth') . '|' . wp_generate_uuid4();
        $instanceId = 'wp-' . substr(hash('sha256', $seed), 0, 32);
        update_option('apd_license_instance_id', $instanceId, false);

        return $instanceId;
    }
}
