<?php

if (!defined('ABSPATH')) {
    die('You are not allowed to call this page directly.');
}

use MemberPress\GroundLevel\Mothership\Credentials;
use MemberPress\GroundLevel\Mothership\Transients\ActivationTransient;

class MeprDrmHelper
{
    const NO_LICENSE_EVENT      = 'no-license';
    const INVALID_LICENSE_EVENT = 'invalid-license';

    const DRM_LOW    = 'low';
    const DRM_MEDIUM = 'medium';
    const DRM_LOCKED = 'locked';

    /**
     * Stores the current DRM status.
     *
     * @var string
     */
    private static $drm_status = '';

    /**
     * Stores the DRM links for different statuses and purposes.
     *
     * @var array|null
     */
    private static $drm_links = null;

    /**
     * Set the DRM status.
     *
     * @param string $status The DRM status to set.
     *
     * @return void
     */
    public static function set_status($status)
    {
        self::$drm_status = $status;
    }

    /**
     * Get the current DRM status.
     *
     * @return string The current DRM status.
     */
    public static function get_status()
    {
        return self::$drm_status;
    }

    /**
     * Check if a license key exists.
     *
     * @return boolean True if a license key exists, false otherwise.
     */
    public static function has_key()
    {
        return !empty(memberpress()->container()->get(Credentials::class)->getLicenseKey());
    }

    /**
     * Get the license key.
     *
     * @return string The license key.
     */
    public static function get_key()
    {
        return memberpress()->container()->get(Credentials::class)->getLicenseKey();
    }

    /**
     * Check if activation override is valid.
     *
     * @return boolean True if activation override is valid, false otherwise.
     */
    public static function is_aov()
    {
        $aov = get_option('mepr_activation_override');

        if (!empty($aov)) {
            return true; // Valid license.
        }

        return false;
    }

    /**
     * Check if the license is valid.
     *
     * @return boolean True if the license is valid, false otherwise.
     */
    public static function is_valid()
    {

        if (self::is_aov() || (class_exists('MeprUpdateCtrl') && MeprUpdateCtrl::is_activated())) {
            return true; // Valid license.
        }

        // Bypass DRM for development/staging sites.
        if (MeprUtils::is_dev_url()) {
            return true; // Valid license for dev environments.
        }

        // Bypass DRM for non-production sites as per wp_get_environment_type().
        if (function_exists('wp_get_environment_type') && wp_get_environment_type() !== 'production') {
            return true; // Valid license for non-producction sites.
        }

        if (!self::has_key()) {
            return false;
        }

        $activation = memberpress()->container()->get(ActivationTransient::class);

        if (empty($activation->licenseKey)) {
            return false;  // Invalid license.
        }

        if ('enabled' !== $activation->licenseStatus) {
            return false; // Invalid license.
        }

        // Expiry is not set. It is unlimited.
        if (empty($activation->licenseExpiresAt)) {
            return true; // Valid license.
        }

        $expiry_stamp = strtotime($activation->licenseExpiresAt);

        // License has a valid expiry date and it is in future?
        if ($expiry_stamp && $expiry_stamp >= time()) {
            return true; // Valid license.
        }

        return false; // Invalid license.
    }

    /**
     * Calculate the number of days elapsed since a given date.
     *
     * @param string $created_at The date to calculate from.
     *
     * @return integer The number of days elapsed.
     */
    public static function days_elapsed($created_at)
    {

        $timestamp = strtotime($created_at);

        if (false === $timestamp) {
            return 0; // Invalid timestamp.
        }

        $start_date = new DateTime(gmdate('Y-m-d'));
        $end_date   = new DateTime(gmdate('Y-m-d', $timestamp));
        $difference = $end_date->diff($start_date);

        return absint($difference->format('%a'));
    }


    /**
     * Determine the DRM status, using a default if not provided.
     *
     * @param string $drm_status The DRM status to check.
     *
     * @return string The determined DRM status.
     */
    protected static function maybe_drm_status($drm_status = '')
    {
        if (empty($drm_status)) {
            $drm_status = self::$drm_status;
        }

        return $drm_status;
    }

    /**
     * Check if the DRM status is locked.
     * When DRM is disabled (e.g. via mepr_drm_enabled filter), returns false so no lock UI is shown.
     *
     * @param string $drm_status The DRM status to check.
     *
     * @return boolean True if the DRM status is locked, false otherwise.
     */
    public static function is_locked($drm_status = '')
    {
        if (! self::is_drm_enabled()) {
            return false;
        }
        return (self::DRM_LOCKED === self::maybe_drm_status($drm_status));
    }

    /**
     * Whether DRM (license-restriction UI: menu, notices, modal, throttle) is enabled.
     * When false, the product never shows locked menu, DRM notices, or modal.
     *
     * @return boolean
     */
    public static function is_drm_enabled()
    {
        return MeprHooks::apply_filters('mepr_drm_enabled', true);
    }

    /**
     * Check if the DRM status is medium.
     *
     * @param string $drm_status The DRM status to check.
     *
     * @return boolean True if the DRM status is medium, false otherwise.
     */
    public static function is_medium($drm_status = '')
    {
        return (self::DRM_MEDIUM === self::maybe_drm_status($drm_status));
    }

    /**
     * Check if the DRM status is low.
     *
     * @param string $drm_status The DRM status to check.
     *
     * @return boolean True if the DRM status is low, false otherwise.
     */
    public static function is_low($drm_status = '')
    {
        return (self::DRM_LOW === self::maybe_drm_status($drm_status));
    }

    /**
     * Get DRM information based on status, event, and purpose.
     *
     * @param string $drm_status The DRM status.
     * @param string $event_name The event name.
     * @param string $purpose    The purpose of the information.
     *
     * @return array The DRM information.
     */
    public static function get_info($drm_status, $event_name, $purpose)
    {

        $out = [];
        switch ($event_name) {
            case self::NO_LICENSE_EVENT:
                $out = self::drm_info_no_license($drm_status, $purpose);
                break;
            case self::INVALID_LICENSE_EVENT:
                $drm_info = self::drm_info_invalid_license($drm_status, $purpose);
                $out      = MeprHooks::apply_filters('mepr_drm_invalid_license_info', $drm_info, $drm_status);
                break;
            default:
        }

        return $out;
    }

    /**
     * Get the status key for a given DRM status.
     *
     * @param string $drm_status The DRM status.
     *
     * @return string The status key.
     */
    public static function get_status_key($drm_status)
    {

        $out = '';
        switch ($drm_status) {
            case self::DRM_LOW:
                $out = 'dl';
                break;
            case self::DRM_MEDIUM:
                $out = 'dm';
                break;
            case self::DRM_LOCKED:
                $out = 'dll';
                break;
            default:
        }

        return $out;
    }

    /**
     * Get the DRM links.
     *
     * @return array The DRM links.
     */
    protected static function get_drm_links()
    {

        if (self::$drm_links === null) {
            self::$drm_links = [
                self::DRM_LOW    => [
                    'email'   => [
                        'home'    => MeprUtils::get_link_url('drm_low_email_home'),
                        'account' => MeprUtils::get_link_url('drm_low_email_account'),
                        'support' => MeprUtils::get_link_url('drm_low_email_support'),
                        'pricing' => MeprUtils::get_link_url('drm_low_email_pricing'),
                    ],
                    'general' => [
                        'home'    => MeprUtils::get_link_url('drm_low_general_home'),
                        'account' => MeprUtils::get_link_url('drm_low_general_account'),
                        'support' => MeprUtils::get_link_url('drm_low_general_support'),
                        'pricing' => MeprUtils::get_link_url('drm_low_general_pricing'),
                    ],
                ],
                self::DRM_MEDIUM => [
                    'email'   => [
                        'home'    => MeprUtils::get_link_url('drm_medium_email_home'),
                        'account' => MeprUtils::get_link_url('drm_medium_email_account'),
                        'support' => MeprUtils::get_link_url('drm_medium_email_support'),
                        'pricing' => MeprUtils::get_link_url('drm_medium_email_pricing'),
                    ],
                    'general' => [
                        'home'    => MeprUtils::get_link_url('drm_medium_general_home'),
                        'account' => MeprUtils::get_link_url('drm_medium_general_account'),
                        'support' => MeprUtils::get_link_url('drm_medium_general_support'),
                        'pricing' => MeprUtils::get_link_url('drm_medium_general_pricing'),
                    ],
                ],
                self::DRM_LOCKED => [
                    'email'   => [
                        'home'    => MeprUtils::get_link_url('drm_locked_email_home'),
                        'account' => MeprUtils::get_link_url('drm_locked_email_account'),
                        'support' => MeprUtils::get_link_url('drm_locked_email_support'),
                        'pricing' => MeprUtils::get_link_url('drm_locked_email_pricing'),
                    ],
                    'general' => [
                        'home'    => MeprUtils::get_link_url('drm_locked_general_home'),
                        'account' => MeprUtils::get_link_url('drm_locked_general_account'),
                        'support' => MeprUtils::get_link_url('drm_locked_general_support'),
                        'pricing' => MeprUtils::get_link_url('drm_locked_general_pricing'),
                    ],
                ],
            ];
        }

        return MeprHooks::apply_filters('mepr_drm_links', self::$drm_links);
    }

    /**
     * Get a specific DRM link based on status, purpose, and type.
     *
     * @param string $drm_status The DRM status.
     * @param string $purpose    The purpose of the link.
     * @param string $type       The type of link.
     *
     * @return string The DRM link.
     */
    public static function get_drm_link($drm_status, $purpose, $type)
    {
        $drm_links = self::get_drm_links();
        if (isset($drm_links[$drm_status])) {
            if (!isset($drm_links[$drm_status][$purpose])) {
                $purpose = 'general';
            }

            if (isset($drm_links[$drm_status][$purpose])) {
                $data = $drm_links[$drm_status][$purpose];
                if (isset($data[$type])) {
                    return $data[$type];
                }
            }
        }

        $fallback_links = [
            'account' => MeprUtils::get_link_url('account'),
            'support' => MeprUtils::get_link_url('support'),
            'pricing' => MeprUtils::get_link_url('pricing'),
        ];

        // Fallback links.
        if (isset($fallback_links[$type])) {
            return $fallback_links[$type];
        }

        return '';
    }

    /**
     * Get the unlicensed-fee disclosure sentence shown on every DRM surface.
     *
     * The percentage is the additional fee on top of the edition's normal
     * rate, so it is accurate for every edition. Returns an empty string when
     * the brand does not define a disclosure percentage (or it rounds to
     * zero).
     *
     * @param float|null $percent Optional percentage; null resolves it from the brand config.
     *
     * @return string The fee disclosure sentence, or an empty string when the brand opted out.
     */
    public static function get_fee_disclosure(?float $percent = null): string
    {
        $display = self::format_fee_disclosure_percent($percent);

        if ('' === $display) {
            return '';
        }

        return sprintf(
            // Translators: %s: fee percentage, e.g. 3 or 7.9.
            __('Note: without an active license, an additional %s%% fee is added to each transaction. Renew your license to remove the fee.', 'memberpress'),
            $display
        );
    }

    /**
     * Format the fee-disclosure percentage for user-facing copy.
     *
     * The single formatter for every DRM surface that prints the percentage,
     * so the number cannot drift between the notices, emails, and the locked
     * modal. Bounds the value to two decimal places (the service-side
     * precision) and trims trailing zeros, so a config value like 3.3333
     * reads as "3.33" and 3.0 as "3". A percentage that is not positive after
     * rounding formats as an empty string — callers must render no disclosure
     * rather than copy with a blank number in it.
     *
     * The default resolves from the `drm_fee_disclosure_percent` brand-config
     * key. It is display-only (the fee actually charged is decided
     * server-side) and a brand-level opt-in: brands that participate in the
     * unlicensed application-fee program define the key in
     * brand/data/config.php in sync with the server-side rate; brands without
     * the key (or with 0) show no fee disclosure.
     *
     * @param float|null $percent Optional percentage; null resolves it from the brand config.
     *
     * @return string The display percentage, or an empty string when there is nothing to disclose.
     */
    public static function format_fee_disclosure_percent(?float $percent = null): string
    {
        $percent ??= (float) MeprUtils::get_brand_config_value('drm_fee_disclosure_percent', 0.0);
        $percent   = round($percent, 2);

        if ($percent <= 0) {
            return '';
        }

        return rtrim(rtrim(number_format($percent, 2, '.', ''), '0'), '.');
    }

    /**
     * Get DRM information for no license event.
     *
     * @param string $drm_status The DRM status.
     * @param string $purpose    The purpose of the information.
     *
     * @return array The DRM information for no license event.
     */
    protected static function drm_info_no_license($drm_status, $purpose)
    {

        $account_link            = self::get_drm_link($drm_status, $purpose, 'account');
        $support_link            = self::get_drm_link($drm_status, $purpose, 'support');
        $pricing_link            = self::get_drm_link($drm_status, $purpose, 'pricing');
        $additional_instructions = sprintf(
            // Translators: %s: site URL.
            __('This is an automated message from %s.', 'memberpress'),
            esc_url(home_url())
        );
        switch ($drm_status) {
            case self::DRM_LOW:
                $admin_notice_view = 'low_warning';
                $heading           = __('MemberPress: Did You Forget Something?', 'memberpress');
                $color             = 'orange';
                $simple_message    = __('Oops! It looks like your MemberPress license key is missing. Here\'s how to fix the problem fast and easy:', 'memberpress');
                $help_message      = __('We’re here if you need any help.', 'memberpress');
                $label             = __('Alert', 'memberpress');
                $activation_link   = admin_url('admin.php?page=memberpress-options#mepr-license');
                $message           = sprintf(
                    '<p>%s</p><ul><li>%s</li><li>%s</li><li>%s</li></ul>',
                    $simple_message,
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('Grab your key from your %1$sAccount Page%2$s.', 'memberpress'),
                        '<a href="' . esc_url($account_link) . '">',
                        '</a>'
                    ),
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('%1$sClick here%2$s to enter and activate it.', 'memberpress'),
                        '<a href="' . esc_url($activation_link) . '">',
                        '</a>'
                    ),
                    __('That’s it!', 'memberpress')
                );
                break;
            case self::DRM_MEDIUM:
                $admin_notice_view = 'medium_warning';
                $heading           = __('MemberPress: WARNING! Your Business is at Risk', 'memberpress');
                $color             = 'orange';
                $simple_message    = __('To continue using MemberPress without interruption, you need to enter your license key right away. Here’s how:', 'memberpress');
                $help_message      = __('Let us know if you need assistance.', 'memberpress');
                $label             = __('Critical', 'memberpress');
                $activation_link   = admin_url('admin.php?page=memberpress-options#mepr-license');
                $message           = sprintf(
                    '<p>%s</p><ul><li>%s</li><li>%s</li><li>%s</li></ul>',
                    $simple_message,
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('Grab your key from your %1$sAccount Page%2$s.', 'memberpress'),
                        '<a href="' . esc_url($account_link) . '">',
                        '</a>'
                    ),
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('%1$sClick here%2$s to enter and activate it.', 'memberpress'),
                        '<a href="' . esc_url($activation_link) . '">',
                        '</a>'
                    ),
                    __('That’s it!', 'memberpress')
                );
                break;
            case self::DRM_LOCKED:
                $admin_notice_view = 'locked_warning';
                $heading           = __('ALERT! MemberPress Backend is Deactivated', 'memberpress');
                $color             = 'red';
                $simple_message    = __('Because your license key is inactive, you can no longer manage MemberPress on the backend (e.g., you can\'t do things like issue customer refunds or add new members). Fortunately, this problem is easy to fix!', 'memberpress');
                $help_message      = __('We\'re here to help you get things up and running. Let us know if you need assistance.', 'memberpress');
                $label             = __('Critical', 'memberpress');
                $activation_link   = admin_url('admin.php?page=memberpress-members');
                $message           = sprintf(
                    '<p>%s</p><ul><li>%s</li><li>%s</li><li>%s</li></ul>',
                    $simple_message,
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('Grab your key from your %1$sAccount Page%2$s.', 'memberpress'),
                        '<a href="' . esc_url($account_link) . '">',
                        '</a>'
                    ),
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('%1$sClick here%2$s to enter and activate it.', 'memberpress'),
                        '<a href="' . esc_url($activation_link) . '">',
                        '</a>'
                    ),
                    __('That’s it!', 'memberpress')
                );
                break;
            default:
                $heading                 = '';
                $color                   = '';
                $message                 = '';
                $help_message            = '';
                $label                   = '';
                $activation_link         = '';
                $admin_notice_view       = '';
                $simple_message          = '';
                $additional_instructions = '';
        }

        $fee_disclosure = self::get_fee_disclosure();
        if ('' !== $message && '' !== $fee_disclosure) {
            $message .= '<p>' . $fee_disclosure . '</p>';
        }

        return compact('heading', 'color', 'message', 'simple_message', 'help_message', 'label', 'activation_link', 'account_link', 'support_link', 'pricing_link', 'admin_notice_view', 'additional_instructions', 'fee_disclosure');
    }

    /**
     * Get DRM information for invalid license event.
     *
     * @param string $drm_status The DRM status.
     * @param string $purpose    The purpose of the information.
     *
     * @return array The DRM information for invalid license event.
     */
    protected static function drm_info_invalid_license($drm_status, $purpose)
    {

        $account_link            = self::get_drm_link($drm_status, $purpose, 'account');
        $support_link            = self::get_drm_link($drm_status, $purpose, 'support');
        $pricing_link            = self::get_drm_link($drm_status, $purpose, 'pricing');
        $additional_instructions = sprintf(
            // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
            __('This is an automated message from %1$s. If you continue getting these messages, please try deactivating and then re-activating your license key on %2$s.', 'memberpress'),
            esc_url(home_url()),
            esc_url(home_url())
        );

        switch ($drm_status) {
            case self::DRM_MEDIUM:
                $admin_notice_view = 'medium_warning';
                $heading           = __('MemberPress: WARNING! Your Business is at Risk', 'memberpress');
                $color             = 'orange';
                $simple_message    = __('Your MemberPress license key is expired, but is required to continue using MemberPress. Fortunately, it’s easy to renew your license key. Just do the following:', 'memberpress');
                $help_message      = __('Let us know if you need assistance.', 'memberpress');
                $label             = __('Critical', 'memberpress');
                $activation_link   = admin_url('admin.php?page=memberpress-options#mepr-license');
                $message           = sprintf(
                    '<p>%s</p><ul><li>%s</li><li>%s</li><li>%s</li></ul>',
                    $simple_message,
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('Go to MemberPress.com and make your selection. %1$sPricing%2$s.', 'memberpress'),
                        '<a href="' . esc_url($pricing_link) . '">',
                        '</a>'
                    ),
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('%1$sClick here%2$s to enter and activate your new license key.', 'memberpress'),
                        '<a href="' . esc_url($activation_link) . '">',
                        '</a>'
                    ),
                    __('That’s it!', 'memberpress')
                );
                break;
            case self::DRM_LOCKED:
                $admin_notice_view = 'locked_warning';
                $label             = __('Critical', 'memberpress');
                $heading           = __('ALERT! MemberPress Backend is Deactivated', 'memberpress');
                $color             = 'red';
                $simple_message    = __('Without an active license key, MemberPress cannot be managed on the backend. Your frontend will remain intact, but you can’t: Issue customer refunds, Add new members, Manage memberships. Fortunately, this problem is easy to fix by doing the following: ', 'memberpress');
                $activation_link   = admin_url('admin.php?page=memberpress-members');
                $message           = sprintf(
                    '<p>%s</p><ul><li>%s</li><li>%s</li><li>%s</li></ul>',
                    $simple_message,
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('Go to MemberPress.com and make your selection. %1$sPricing%2$s.', 'memberpress'),
                        '<a href="' . esc_url($pricing_link) . '">',
                        '</a>'
                    ),
                    sprintf(
                        // Translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
                        __('%1$sClick here%2$s to enter and activate your new license key.', 'memberpress'),
                        '<a href="' . esc_url($activation_link) . '">',
                        '</a>'
                    ),
                    __('That’s it!', 'memberpress')
                );
                $help_message = __('We’re here to help you get things back up and running. Let us know if you need assistance.', 'memberpress');
                break;
            default:
                $heading                 = '';
                $color                   = '';
                $message                 = '';
                $help_message            = '';
                $label                   = '';
                $activation_link         = '';
                $admin_notice_view       = '';
                $simple_message          = '';
                $additional_instructions = '';
        }

        $fee_disclosure = self::get_fee_disclosure();
        if ('' !== $message && '' !== $fee_disclosure) {
            $message .= '<p>' . $fee_disclosure . '</p>';
        }

        return compact('heading', 'color', 'message', 'simple_message', 'help_message', 'label', 'activation_link', 'account_link', 'support_link', 'admin_notice_view', 'pricing_link', 'additional_instructions', 'fee_disclosure');
    }

    /**
     * Parse event arguments from a JSON string.
     *
     * @param string $args The JSON string of arguments.
     *
     * @return array The parsed event arguments.
     */
    public static function parse_event_args($args)
    {
        return json_decode($args, true);
    }

    /**
     * Prepare a dismissable notice key for a given notice.
     *
     * @param string $notice The notice identifier.
     *
     * @return string The dismissable notice key.
     */
    public static function prepare_dismissable_notice_key($notice)
    {
        $notice = sanitize_key($notice);
        return "{$notice}_u" . get_current_user_id();
    }

    /**
     * Check if a notice is dismissed based on event data and notice key.
     *
     * @param array  $event_data The event data.
     * @param string $notice_key The notice key.
     *
     * @return boolean True if the notice is dismissed, false otherwise.
     */
    public static function is_dismissed($event_data, $notice_key)
    {
        if (isset($event_data[$notice_key])) {
            $diff = (int) abs(time() - $event_data[$notice_key]);
            if ($diff <= (HOUR_IN_SECONDS * 24)) {
                return true;
            }
        }

        return false;
    }
}
