<?php

// Will rely on pmpro library instead, this kept in case of future use
//require_once CHURNSOLUTION_DIR . '/vendor/autoload.php';

if (!defined('ABSPATH')) exit;

add_action('plugins_loaded', array('Churnsolution_Stripe_Gateway', 'init'));

class Churnsolution_Stripe_Gateway
{

    private static $stripe;

    public static function init()
    {

        $secret_key = null;

        if (class_exists("PMProGateway_stripe")) {
            PMProGateway_stripe::loadStripeLibrary();
        }

        if (class_exists("PMPro_Subscription")) {

            $secret_key = self::pmpro_get_secret_key();
        }

        if (!empty($secret_key)) {
            self::$stripe = new Stripe\StripeClient($secret_key);
        }
    }

    public static function pause($external_id, $number_of_months)
    {
        self::validate_stripe_initialized();

        $subscription = self::validate_subscription_exists($external_id);

        $current_period_end = $subscription->current_period_end;
        $new_period_end = $current_period_end + $number_of_months * 30 * 24 * 60 * 60;

        $subscription = self::$stripe->subscriptions->update(
            $external_id,
            ['pause_collection' => array(
                'resumes_at' => $new_period_end,
                'behavior' => 'mark_uncollectible'
            )]
        );

    }

    public static function apply_coupon($external_id, $coupon_code)
    {
        self::validate_stripe_initialized();

        $subscription = self::validate_subscription_exists($external_id);

        $subscription = self::$stripe->subscriptions->update(
            $external_id,
            ['coupon' => $coupon_code]
        );

    }

    public static function extend_free_trial($external_id, $number_of_days)
    {
        self::validate_stripe_initialized();

        $subscription = self::validate_subscription_exists($external_id);

        if ($subscription->status != Stripe\Subscription::STATUS_TRIALING) {
            throw new Exception("subscription: " . esc_attr($external_id) . " is not trialing", 400);
        }

        $current_trial_end = $subscription->trial_end; // in seconds
        $new_trial_end = $current_trial_end + $number_of_days * 24 * 60 * 60;

        $subscription = self::$stripe->subscriptions->update(
            $external_id,
            ['trial_end' => $new_trial_end]
        );

    }


    public static function cancel_subscription_via_pmpro(WP_User $user, $level_id)
    {

        if (!class_exists("PMPro_Subscription")) {
            return;
        }

        $user_id = $user->ID;
        $subscriptions = PMPro_Subscription::get_subscriptions_for_user($user_id, $level_id);

        if (empty($subscriptions)) {
            return;
        }

        foreach ($subscriptions as $subscription) {

            $next_payment_date = $subscription->get_next_payment_date();
            // Set the enddate to the next payment date.
            pmpro_set_expiration_date( $user_id, $level_id, $next_payment_date );

            // Cancel the subscriptions.
            $subscription->cancel_at_gateway();

            // Send an email to the member.
            $myemail = new PMProEmail();
            $myemail->sendCancelOnNextPaymentDateEmail( $user, $level_id );

            // Send an email to the admin.
            $myemail = new PMProEmail();
            $myemail->sendCancelOnNextPaymentDateAdminEmail( $user, $level_id );

        }

    }

    private static function validate_subscription_exists($external_id)
    {
        self::validate_stripe_initialized();

        try {
            return self::$stripe->subscriptions->retrieve($external_id);
        } catch (\Stripe\Exception\ApiErrorException $e) {
            $code = $e->getStripeCode();

            if ($code == \Stripe\ErrorObject::CODE_RESOURCE_MISSING) {
                throw new Exception(
                    "No subscriptions with id: " . esc_attr($external_id) . " were found",
                    404
                );
            }

            throw $e;
        }
    }

    public static function sync_pmpro_subscription($user_id)
    {

        if (!class_exists("PMPro_Subscription") or !class_exists("PMPro_Membership_Level")) {
            return;
        }

        $pmpro_subscriptions = PMPro_Subscription::get_subscriptions_for_user($user_id);

        foreach ($pmpro_subscriptions as $pmpro_subscription) {

            // Update next payment date
            $pmpro_subscription->update();

            // Plan changes updates
            $external_id = $pmpro_subscription->get_subscription_transaction_id();
            $external_subscription = self::$stripe->subscriptions->retrieve($external_id);

            if (empty($external_subscription)) {
                continue;
            }

            // Get product id
            $items = $external_subscription->items;
            $item = $items->data[0];
            $price = $item->price;
            $product_id = $price->product;

            // get level id by product id
            $external_level_id = self::get_level_from_product_id($product_id);

            // if level not found, do nothing
            if(empty($external_level_id)){
                continue;
            }

            $current_level_id = $pmpro_subscription->get_membership_level_id();

            // if same, nothing to sync
            if ($current_level_id == $external_level_id) {
                continue;
            }

            $membership_level = new PMPro_Membership_Level($external_level_id);

            global $wpdb;

            // update level in database
            $wpdb->update(
                $wpdb->prefix . 'pmpro_memberships_users',
                array(
                    'membership_id' => $external_level_id,
                    'billing_amount' => $membership_level->billing_amount,
                    'cycle_period' => $membership_level->cycle_period
                ),
                array(
                    'user_id' => $user_id,
                    'status' => 'active',
                    'membership_id' => $current_level_id
                )
            );

            $wpdb->update(
                $wpdb->prefix . 'pmpro_subscriptions',
                array(
                    'membership_level_id' => $external_level_id,
                    'billing_amount' => $membership_level->billing_amount,
                    'cycle_period' => $membership_level->cycle_period
                ),
                array(
                    'user_id' => $user_id,
                    'status' => 'active',
                    'membership_level_id' => $current_level_id
                )
            );
        }

    }

    public static function get_external_subscription($external_id)
    {
        self::validate_stripe_initialized();

        try {
            $external_subscription = self::$stripe->subscriptions->retrieve($external_id);
        } catch (\Stripe\Exception\ApiErrorException $e) {
            return null;
        }
        return $external_subscription;
    }

    public static function get_external_upcoming_invoice($external_id)
    {
        self::validate_stripe_initialized();

        try {
            $upcoming_invoice = self::$stripe->invoices->createPreview(['subscription' => $external_id]);
        } catch (\Stripe\Exception\ApiErrorException $e) {
            return null;
        }
        return $upcoming_invoice;
    }

    public static function get_level_from_product_id($product_id)
    {
        global $wpdb;

        $sql_query = $wpdb->prepare("
                    SELECT * 
                    FROM `$wpdb->pmpro_membership_levelmeta` 
                    WHERE meta_value = %s",
            esc_sql($product_id)
        );

        $membership_levelmeta_rows = $wpdb->get_results($sql_query);

        if (empty($membership_levelmeta_rows)) {
            return null;
        }

        $membership_levelmeta = $membership_levelmeta_rows[0];


        return $membership_levelmeta->pmpro_membership_level_id;
    }

    private static function pmpro_is_using_legacy_keys()
    {
        $r = !empty(get_option('pmpro_stripe_secretkey')) && !empty(get_option('pmpro_stripe_publishablekey'));
        return $r;
    }

    private static function pmpro_get_secret_key()
    {
        if (self::pmpro_is_using_legacy_keys()) {
            $secretkey = get_option('pmpro_stripe_secretkey');
        } else {
            $secretkey = get_option('pmpro_gateway_environment') === 'live'
                ? get_option('pmpro_live_stripe_connect_secretkey')
                : get_option('pmpro_sandbox_stripe_connect_secretkey');
        }
        return $secretkey;
    }

    private static function validate_stripe_initialized()
    {
        if (empty(self::$stripe)) {
            throw new Exception("Stripe is not configured properly", 400);
        }
    }
    public static function pmpro_get_secrets()
    {
        $connectSecretKey = null;
        $connectPublishableKey = null;
        $legacySecretKey = null;
        $legacyPublishableKey = null;
        $liveMode = get_option('pmpro_gateway_environment') === 'live';

        if (self::pmpro_is_using_legacy_keys()) {
            $legacySecretKey = get_option('pmpro_stripe_secretkey');
            $legacyPublishableKey = get_option('pmpro_stripe_publishablekey');
        } else {
            $connectSecretKey = get_option('pmpro_gateway_environment') === 'live'
                ? get_option('pmpro_live_stripe_connect_secretkey')
                : get_option('pmpro_sandbox_stripe_connect_secretkey');

            $connectPublishableKey = get_option('pmpro_gateway_environment') === 'live'
                ? get_option('pmpro_live_stripe_connect_publishablekey')
                : get_option('pmpro_sandbox_stripe_connect_publishablekey');
        }

        return [
            "connect_public_key" => $connectPublishableKey,
            "connect_private_key" => $connectSecretKey,
            "legacy_private_key" => $legacySecretKey,
            "legacy_public_key" => $legacyPublishableKey,
            "live_mode" => $liveMode
        ];
    }

}