<?php

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

class MeprDrmAppFee
{
    /**
     * Enables the DRM application fee.
     * The unified mapper (scheduled by MeprDrmCtrl) will detect the change on the next run.
     *
     * @return void
     */
    public function do_app_fee()
    {
        MeprDrmHelper::enable_app_fee();
        wp_clear_scheduled_hook('mepr_drm_app_fee_mapper', [false]);
    }

    /**
     * Disables the DRM application fee.
     * The unified mapper will detect the change on the next run.
     *
     * @return void
     */
    public function undo_app_fee()
    {
        if (! MeprDrmHelper::is_app_fee_enabled()) {
            return;
        }

        MeprDrmHelper::disable_app_fee();
        wp_clear_scheduled_hook('mepr_drm_app_fee_mapper', [false]);
    }

    /**
     * Schedules the daily DRM fee revision cron (refreshes DRM base fee from API).
     *
     * @return void
     */
    public function do_app_fee_revision()
    {
        if (! wp_next_scheduled('mepr_drm_app_fee_revision', [false])) {
            wp_schedule_event(time(), 'daily', 'mepr_drm_app_fee_revision', [false]);
        }
    }

    /**
     * Initializes DRM-specific cron jobs.
     * The unified mapper is scheduled separately by MeprDrmCtrl.
     *
     * @return void
     */
    public function init_crons()
    {
        $this->do_app_fee_revision();
    }

    /**
     * Retrieves Stripe connected payment methods.
     *
     * @return array List of connected payment methods
     */
    private function get_stripe_connected_payment_methods()
    {
        $mepr_options = MeprOptions::fetch();
        $pmt_methods  = $mepr_options->payment_methods();
        $methods      = [];

        foreach ($pmt_methods as $key => $method) {
            if ($method instanceof MeprStripeGateway && MeprStripeGateway::is_stripe_connect($key)) {
                // Skip gateways in countries where Stripe doesn't support application fees.
                $country = MeprStripeGateway::get_account_country($key);
                if (false !== $country && ! MeprDrmHelper::is_country_unlockable_by_fee($country)) {
                    continue;
                }

                $methods[] = $key;
            }
        }

        return $methods;
    }

    /**
     * Retrieves all active subscriptions.
     *
     * @param  array   $params An array of parameters to filter the subscriptions.
     * @param  integer $limit  The maximum number of subscriptions to retrieve.
     * @param  boolean $count  A boolean indicating whether to return a count of subscriptions.
     * @return array|integer List of active subscriptions or count of subscriptions
     */
    public function get_all_active_subs($params = [], $limit = '30', $count = false)
    {
        global $wpdb;

        $payment_methods = $this->get_stripe_connected_payment_methods();
        if (empty($payment_methods) || !is_array($payment_methods)) {
            return -1; // Nothing to process.
        }

        $mepr_db = new MeprDb();

        $limit_int = ('' !== $limit && is_numeric($limit)) ? (int) $limit : 0;
        $fields    = $count ? 'COUNT(*)' : 'sub.gateway, sub.id, sub.subscr_id, sub.price';
        $in_placeholders = implode(',', array_fill(0, count($payment_methods), '%s'));

        $sql = "
      SELECT {$fields}
        FROM {$mepr_db->subscriptions} AS sub
          JOIN {$mepr_db->transactions} AS t
            ON sub.id = t.subscription_id
    ";

        if (isset($params['mepr_app_fee_not_applied']) && true === $params['mepr_app_fee_not_applied']) {
            $sql .= "
        LEFT JOIN {$mepr_db->subscription_meta} AS sm_fee
            ON sub.id = sm_fee.subscription_id
            AND sm_fee.meta_key = 'application_fee_percent'
      ";
        }

        if (
            ( isset($params['mepr_app_not_fee_version']) && true === $params['mepr_app_not_fee_version'] ) ||
            ( isset($params['mepr_app_fee_applied']) && true === $params['mepr_app_fee_applied'] )
        ) {
            $sql .= "
        JOIN {$mepr_db->subscription_meta} AS sm_version
            ON sub.id = sm_version.subscription_id
            AND sm_version.meta_key = 'application_fee_version'
      ";
        }

        if (isset($params['mepr_app_fee_mismatch']) && is_numeric($params['mepr_app_fee_mismatch'])) {
            $sql .= "
        LEFT JOIN {$mepr_db->subscription_meta} AS sm_mismatch
            ON sub.id = sm_mismatch.subscription_id
            AND sm_mismatch.meta_key = 'application_fee_percent'
      ";
        }

        $sql .= "
      WHERE t.status IN(%s,%s)
          AND sub.status = %s
          AND sub.gateway IN ({$in_placeholders})
        AND t.expires_at > %s AND t.expires_at != '0000-00-00 00:00:00'
    ";

        if (isset($params['mepr_app_fee_not_applied']) && true === $params['mepr_app_fee_not_applied']) {
            $sql .= '
        AND sm_fee.subscription_id IS NULL
      ';
        }

        if (isset($params['mepr_app_not_fee_version']) && true === $params['mepr_app_not_fee_version']) {
            $sql .= '
        AND sm_version.meta_value != %s
      ';
        }

        if (isset($params['mepr_app_fee_mismatch']) && is_numeric($params['mepr_app_fee_mismatch'])) {
            $sql .= '
        AND (ROUND(CAST(sm_mismatch.meta_value AS DECIMAL(10,4)), 2) != ROUND(%f, 2) OR sm_mismatch.meta_value IS NULL)
      ';
        }

        $sql .= '
      ORDER BY t.expires_at ASC
    ';

        if ($limit_int > 0) {
            $sql .= '
      LIMIT %d
    ';
        }

        $prepare_args = array_merge(
            [
                MeprTransaction::$complete_str,
                MeprTransaction::$confirmed_str,
                MeprSubscription::$active_str,
            ],
            $payment_methods,
            [MeprUtils::db_now()]
        );
        if (isset($params['mepr_app_not_fee_version']) && true === $params['mepr_app_not_fee_version']) {
            $prepare_args[] = $params['drm_fee_api_version'];
        }
        if (isset($params['mepr_app_fee_mismatch']) && is_numeric($params['mepr_app_fee_mismatch'])) {
            $prepare_args[] = round((float) $params['mepr_app_fee_mismatch'], 2);
        }
        if ($limit_int > 0) {
            $prepare_args[] = $limit_int;
        }

        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query uses placeholders; all dynamic values are in $prepare_args.
        $sql = $wpdb->prepare($sql, ...$prepare_args);

        if ($count) {
            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter
            return $wpdb->get_var($sql);
        } else {
            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter
            return $wpdb->get_results($sql);
        }
    }

    /**
     * Processes the application fee for subscriptions.
     *
     * @param  array   $subscriptions      An array of subscription objects to process.
     * @param  string  $api_version        The version of the API to use.
     * @param  float   $current_percentage The current percentage of the application fee.
     * @param  boolean $delete_metadata    A boolean indicating whether to delete metadata.
     * @return integer|void Number of updated subscriptions
     */
    public function process_subscriptions_fee($subscriptions, $api_version, $current_percentage, $delete_metadata = false)
    {

        if (! is_array($subscriptions) || empty($subscriptions)) {
            return;
        }

        $mepr_db      = new MeprDb();
        $mepr_options = MeprOptions::fetch();

        $updated = 0;

        foreach ($subscriptions as $subscription) {
            try {
                $pm            = $mepr_options->payment_method($subscription->gateway);
                $json_response = $pm->send_stripe_request('subscriptions/' . $subscription->subscr_id, [
                    'application_fee_percent' => $current_percentage,
                ], 'post');

                if (is_array($json_response) && ! empty($json_response)) {
                      $updated++;

                    if ($delete_metadata) {
                        $mepr_db->delete_metadata($mepr_db->subscription_meta, 'subscription_id', $subscription->id, 'application_fee_percent');
                        $mepr_db->delete_metadata($mepr_db->subscription_meta, 'subscription_id', $subscription->id, 'application_fee_version');
                        $mepr_db->update_metadata($mepr_db->subscription_meta, 'subscription_id', $subscription->id, 'application_fee_revoked', MeprUtils::db_now());
                    } else {
                        $mepr_db->update_metadata($mepr_db->subscription_meta, 'subscription_id', $subscription->id, 'application_fee_percent', $current_percentage);
                        $mepr_db->update_metadata($mepr_db->subscription_meta, 'subscription_id', $subscription->id, 'application_fee_version', $api_version);
                    }
                }
            } catch (Exception $ex) {
                // Silently continue processing other subscriptions if API call fails.
            }
        }

        return $updated;
    }
}
