<?php

defined( 'ABSPATH' ) or exit;

function pwlpar_get_member( $user_id ) {
    global $wpdb;

    $user = get_user_by( 'id', $user_id );

    if ( is_a( $user, 'WP_User' ) ) {
        $member = new PWLPAR_Member( array(
            'id'            => $user->ID,
            'display_name'  => $user->display_name,
            'login'         => $user->user_login,
            'email'         => $user->user_email,
            'is_enrolled'   => get_user_meta( $user->ID, PWLPAR_USER_META_KEY_IS_MEMBER, true ),
            'join_date'     => get_user_meta( $user->ID, PWLPAR_USER_META_KEY_JOIN_DATE, true ),
        ) );
    } else {
        $member = false;
    }

    return apply_filters( 'pwlpar_get_member', $member );
}

function pwlpar_get_members( $args = array() ) {
    global $wpdb, $pwlpardb;

    $default_args = array(
        'search' => false,
        'limit' => -1,
        'offset' => 0,
    );

    $args = wp_parse_args( $args, $default_args );

    $where = '';
    if ( $args['search'] ) {
        $search = '%' . $wpdb->esc_like( $args['search'] ) . '%';
        $where .= $wpdb->prepare( "AND ( u.display_name LIKE %s OR u.user_login LIKE %s OR u.user_email LIKE %s )", $search, $search, $search );
    }

    // $where is prepared so this warning can be silenced.
    // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $results = $wpdb->get_results( $wpdb->prepare( "
        SELECT
            u.id,
            u.display_name,
            u.user_login AS login,
            u.user_email AS email,
            (SELECT meta_value FROM %i WHERE user_id = m.user_id AND meta_key = %s LIMIT 1) AS join_date,
            (
                SELECT
                    SUM(points)
                FROM
                    %i AS t
                WHERE
                    t.user_id = m.user_id
                    AND t.status = 'active'
            ) AS balance,
            SUM( CASE WHEN s.parent_id = 0 THEN 1 ELSE 0 END ) AS total_orders,
            SUM( s.total_sales ) AS total_revenue,
            CASE WHEN SUM( CASE WHEN s.parent_id = 0 THEN 1 ELSE 0 END ) = 0 THEN NULL ELSE SUM( s.total_sales ) / SUM( CASE WHEN s.parent_id = 0 THEN 1 ELSE 0 END ) END AS average_order_value
        FROM
            %i AS m
        JOIN
            %i AS u ON (u.ID = m.user_id)
        LEFT JOIN
            %i AS c ON (c.user_id = m.user_id)
        LEFT JOIN
            %i AS s ON (c.customer_id = s.customer_id AND ( s.status NOT IN ( 'wc-auto-draft','wc-trash','wc-pending','wc-failed','wc-cancelled','wc-checkout-draft' ) ))
        WHERE
            m.meta_key = %s
            AND m.meta_value = 'yes'
            $where
        GROUP BY
            u.id
        ORDER BY
            balance DESC,
            u.user_login
        ",
        $wpdb->usermeta,
        PWLPAR_USER_META_KEY_JOIN_DATE,
        $pwlpardb->transaction,
        $wpdb->usermeta,
        $wpdb->users,
        $wpdb->prefix . 'wc_customer_lookup',
        $wpdb->prefix . 'wc_order_stats',
        PWLPAR_USER_META_KEY_IS_MEMBER
    ), ARRAY_A );
    // phpcs:enable

    $members = array();
    foreach ( $results as $result ) {
        $members[] = new PWLPAR_Member( $result );
    }

    return apply_filters( 'pwlpar_get_members', $members );
}

function pwlpar_get_member_count() {
    global $wpdb;

    $user_query = new WP_User_Query( array(
        'meta_key'   => PWLPAR_USER_META_KEY_IS_MEMBER,
        'meta_value' => 'yes',
        'fields'     => 'ID',
    ) );

    return count( $user_query->get_results() );
}

function pwlpar_get_member_revenue() {
    // Get users who have the required meta key and value.
    $customer_ids = get_users( array(
        'meta_key'   => PWLPAR_USER_META_KEY_IS_MEMBER,
        'meta_value' => 'yes',
        'fields'     => 'ID',
    ) );

    if ( empty( $customer_ids ) ) {
        return 0;
    }

    $orders = wc_get_orders( array(
        'customer_id' => $customer_ids,
        'status'      => [ 'completed', 'processing', 'on-hold', 'refunded' ],
        'limit'       => -1,
        'return'      => 'objects',
    ) );

    $total_revenue = 0;

    foreach ( $orders as $order ) {
        $total_revenue += (float) $order->get_total();
    }

    return $total_revenue;
}

function pwlpar_current_user_is_rewards_member() {
    return pwlpar_user_is_rewards_member( get_current_user_id() );
}

function pwlpar_user_is_rewards_member( $user_id ) {
    $is_member = false;

    if ( is_a( $user_id, 'PWLPAR_Member' ) ) {
        $member = $user_id;
    } else {
        $member = pwlpar_get_member( $user_id );
    }

    if ( $member ) {
        $is_member = $member->get_is_enrolled();
    }

    return apply_filters( 'pwlpar_user_is_rewards_member', $is_member, $user_id );
}

function pwlpar_enroll_user( $user_id ) {
    $member = pwlpar_get_member( $user_id );
    if ( !$member ) {
        return __( 'Member not found.', 'pw-loyalty-points-and-rewards-for-woocommerce' );
    }

    if ( !$member->get_is_enrolled() ) {
        $member->set_is_enrolled( 'yes' );
        $member->set_join_date( current_time( 'mysql', true ) );
    }

    $member->save();

    // Don't grant a bonus if they have any past transactions.
    $past_transactions = pwlpar_get_transactions( array( 'user_id' => $user_id ) );

    if ( !empty( pwlpar_signup_bonus_points() ) ) {
        // Don't grant a bonus if they have any past transactions.
        if ( empty( $past_transactions ) ) {
            $result = pwlpar_add_signup_bonus_points( $member );

            if ( !is_numeric( $result ) ) {
                pwlpar_log( 'pwlpar_enroll_user() pwlpar_add_signup_bonus_points() result: ' . $result, 'error' );
            }
        }
    }

    return true;
}

function pwlpar_unenroll_user( $user_id ) {
    $member = pwlpar_get_member( $user_id );
    if ( $member ) {
        $member->set_is_enrolled( 'no' );
        $member->set_join_date( '' );
        $id = $member->save();
        return !empty( $id );
    } else {
        return __( 'Member not found.', 'pw-loyalty-points-and-rewards-for-woocommerce' );
    }
}

function pwlpar_current_user_point_balance( $formatted = false ) {
    return pwlpar_get_member_point_balance( get_current_user_id(), $formatted );
}

function pwlpar_get_member_point_balance( $member, $formatted = false ) {
    global $wpdb, $pwlpardb;

    $balance = 0;

    if ( !is_a( $member, 'PWLPAR_Member' ) ) {
        $user_id = absint( $member );
        if ( !empty( $user_id ) ) {
            $member = pwlpar_get_member( $user_id );
        } else {
            return 0;
        }
    }

    if ( !empty( $member->get_id() ) ) {
        // Using a custom table, not a WordPress table, so this warning can be ignored.
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $balance = (float) $wpdb->get_var( $wpdb->prepare( "SELECT SUM(points) FROM %i WHERE user_id = %d AND status = 'active';", $pwlpardb->transaction, $member->get_id() ) );
    }

    if ( $formatted ) {
        $balance = pwlpar_format_points( $balance );
    }

    $balance = apply_filters( 'pwlpar_get_member_point_balance', $balance, $member, $formatted );

    return $balance;
}

function pwlpar_delete_member( $member, $reassign ) {
    global $wpdb, $pwlpardb;

    $user_id = $member->get_id();
    $reassign = absint( $reassign );

    // Using a custom table, not a WordPress table, so this warning can be ignored.
    // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

    // Rewards.
    if ( empty( $reassign ) || $reassign == $user_id ) {
        $result = $wpdb->delete( $pwlpardb->reward, array( 'user_id' => $user_id ) );
    } else {
        $result = $wpdb->update( $pwlpardb->reward, array( 'user_id' => $reassign ), array( 'user_id' => $user_id ) );
    }
    if ( false === $result ) {
        wp_die( esc_html( $wpdb->last_error ) );
    }

    // Transactions.
    if ( empty( $reassign ) || $reassign == $user_id ) {
        $result = $wpdb->delete( $pwlpardb->transaction, array( 'user_id' => $user_id ) );
    } else {
        $result = $wpdb->update( $pwlpardb->transaction, array( 'user_id' => $reassign ), array( 'user_id' => $user_id ) );
    }
    if ( false === $result ) {
        wp_die( esc_html( $wpdb->last_error ) );
    }

    // phpcs:enable
}
