<?php

defined( 'ABSPATH' ) or exit;

function pwlpar_get_offer_coupon_types() {
    $types = array(
        'fixed_cart' => __( 'Fixed cart discount', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
        'percent' => __( 'Percentage discount', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
        'free_product' => __( 'Free product(s)', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
        'bonus_points' => __( 'Bonus points', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
    );

    return apply_filters( 'pwlpar_get_offer_coupon_types', $types );
}

function pwlpar_get_offer_coupon_type_description( $type ) {
    $descriptions = array(
        'fixed_cart' => __( 'Apply a fixed total discount to the entire cart.', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
        'percent' => __( 'Apply a percentage discount to the entire cart.', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
        'free_product' => __( 'Offer one or more products for free.', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
        'bonus_points' => __( 'Adds points to the customer\'s account.', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
    );

    $description = isset( $descriptions[ $type ] ) ? $descriptions[ $type ] : $type;

    return apply_filters( 'pwlpar_get_offer_coupon_type_description', $description, $type );
}

function pwlpar_get_offer_coupon_type_name( $coupon_type ) {
    $types = pwlpar_get_offer_coupon_types();
    return isset( $types[ $coupon_type ] ) ? $types[ $coupon_type ] : $coupon_type;
}

function pwlpar_get_offer( $id ) {
    $id = absint( $id );

    if ( empty( $id ) ) {
        return new PWLPAR_Offer();
    }

    $offers = pwlpar_get_offers( array(
        'id' => $id,
    ) );

    if ( count( $offers ) == 1 ) {
        return $offers[0];
    } else {
        return new PWLPAR_Offer();
    }

    return apply_filters( 'pwlpar_get_offer', $offer, $id );
}

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

    $default_args = array(
        'active' => 'any',
        'pimwick_rewards_offer_id' => 'any',
        'user_id' => 'any',
        'status' => 'any',
        'status__in' => array(),
        'status__not_in' => array(),
    );

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

    if ( isset( $args['id'] ) && $args['pimwick_rewards_offer_id'] == 'any' ) {
        $args['pimwick_rewards_offer_id'] = $args['id'];
    }

    $offers = array();

    $where = '1 = 1';
    $where .= pwlpar_get_sql_where( 'o.pimwick_rewards_offer_id', $args['pimwick_rewards_offer_id'] );
    $where .= pwlpar_get_sql_where( 'o.status', $args['status'] );
    $where .= pwlpar_get_sql_where( 'o.status', $args['status__in'] );
    $where .= pwlpar_get_sql_where( 'o.status', $args['status__not_in'], true );

    if ( $args['active'] === true ) {
        $where .= "
            AND o.status = 'publish'
        ";
    }

    //
    // $where value is escaped inside the pwlpar_get_sql_where() function preventing SQL injection.
    //
    // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $results = $wpdb->get_results( $wpdb->prepare( "
        SELECT
            o.*
        FROM
            %i AS o
        WHERE
            $where
        ORDER BY
            o.menu_order ASC,
            o.title ASC,
            o.pimwick_rewards_offer_id DESC
        ",
        $pwlpardb->offer
    ), ARRAY_A );
    // phpcs:enable

    foreach ( $results as $row ) {
        $offers[] = new PWLPAR_Offer( $row );
    }

    return apply_filters( 'pwlpar_get_offers', $offers, $args );
}

function pwlpar_get_top_offers( $limit = 3 ) {
    global $wpdb, $pwlpardb;

    // Querying custom tables so these warnings can be ignored.
    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $results = $wpdb->get_results( $wpdb->prepare( "
        SELECT
            o.*,
            COUNT(*) AS claimed_count
        FROM
            %i AS o
        JOIN
            %i AS r ON (o.pimwick_rewards_offer_id = r.pimwick_rewards_offer_id)
        WHERE
            o.status != 'trash'
            AND r.status != 'trash'
        GROUP BY
            o.pimwick_rewards_offer_id
        ORDER BY
            claimed_count DESC,
            o.menu_order ASC
        LIMIT
            %d
        ",
        $pwlpardb->offer,
        $pwlpardb->reward,
        absint( $limit )
    ) );

    $top_offers = array();
    foreach ( $results as $row ) {
        $top_offers[] = array(
            'offer' => new PWLPAR_Offer( $row ),
            'claimed_count' => absint( $row->claimed_count ),
        );
    }

    return apply_filters( 'pwlpar_get_top_offers', $top_offers, $limit );
}

function pwlpar_offer_claimed_count( $offer_id, $user_id = false ) {
    global $wpdb, $pwlpardb;

    $offer_id = absint( $offer_id );
    $user_id = $user_id ? absint( $user_id ) : get_current_user_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
    $claimed_count = $wpdb->get_var( $wpdb->prepare( "
        SELECT
            COUNT(*)
        FROM
            %i AS r
        WHERE
            r.pimwick_rewards_offer_id = %d
            AND r.user_id = %d
            AND r.status != 'trash'
        ",
        $pwlpardb->reward,
        $offer_id,
        $user_id
    ) );

    return apply_filters( 'pwlpar_offer_claimed_count', $claimed_count, $offer_id, $user_id );
}

function pwlpar_claim_offer( $offer_id ) {
    global $wpdb, $pwlpardb;

    if ( !pwlpar_current_user_is_rewards_member() ) {
        return __( 'You are not a rewards member.', 'pw-loyalty-points-and-rewards-for-woocommerce' );
    }

    $offer_id = absint( $offer_id );
    if ( empty( $offer_id ) ) {
        return __( 'Missing Offer ID', 'pw-loyalty-points-and-rewards-for-woocommerce' );
    }

    $offer = pwlpar_get_offer( $offer_id );
    if ( empty( $offer ) || $offer->get_id() != $offer_id ) {
        return __( 'Invalid Offer ID', 'pw-loyalty-points-and-rewards-for-woocommerce' ) . ' ' . $offer_id;
    }

    $user_id = get_current_user_id();
    $points = absint( $offer->get_points( 'edit' ) );
    $balance = pwlpar_current_user_point_balance();

    $can_claim_offer = $offer->get_user_can_claim_offer( $user_id );

    if ( $can_claim_offer !== true ) {
        return $can_claim_offer;
    }

    $reward = new PWLPAR_Reward( array(
        'offer'                     => $offer,
        'pimwick_rewards_offer_id'  => $offer->get_id(),
        'user_id'                   => $user_id,
    ) );
    $reward->save();

    if ( empty( $reward->get_id() ) ) {
        pwlpar_log( 'pwlpar_claim_offer() failed to save reward: ' . $wpdb->last_error, 'error' );
        return __( 'Failed to save reward.', 'pw-loyalty-points-and-rewards-for-woocommerce' ) . ' ' . $wpdb->last_error;
    }

    /* translators: %s is the offer title. */
    $note = sprintf( __( 'Claimed offer: %s', 'pw-loyalty-points-and-rewards-for-woocommerce' ), $offer->get_title() );

    $transaction_id = pwlpar_add_transaction( array(
        'user_id' => $user_id,
        'points' => ( $points * -1 ),
        'note' => $note,
        'redeemed_reward_id' => $reward->get_id(),
    ) );
    if ( !is_numeric( $transaction_id ) ) {
        return $transaction_id;
    }

    pwlpar_apply_reward( $reward );

    return true;
}

function pwlpar_get_offer_edit_url( $offer_id ) {
    $url = pwlpara_admin_url( 'offers', array( 'id' => $offer_id ) );
    return apply_filters( 'pwlpar_get_offer_edit_url', $url, $offer_id );
}
