<?php

defined( 'ABSPATH' ) or exit;

class PWLPAR_Offer {

    protected $id;
    protected $title;
    protected $description;
    protected $coupon_amount;
    protected $points;
    protected $free_shipping;
    protected $individual_use;
    protected $exclude_sale_items;
    protected $menu_order;
    protected $status;
    protected $create_date_gmt;
    protected $create_user_id;
    protected $update_date_gmt;
    protected $update_user_id;

    protected $statistics_cache;
    protected $restrictions_cache;

    function __construct( $args = array() ) {

        $default_args = apply_filters( 'pwlpar_offer_default_args', array(
            'pimwick_rewards_offer_id'              => 0,
            'title'                                 => __( 'Offer', 'pw-loyalty-points-and-rewards-for-woocommerce' ),
            'description'                           => null,
            'coupon_amount'                         => null,
            'points'                                => null,
            'free_shipping'                         => null,
            'individual_use'                        => null,
            'exclude_sale_items'                    => null,
            'menu_order'                            => 0,
            'status'                                => 'publish',
            'create_date_gmt'                       => current_time( 'mysql', true ),
            'create_user_id'                        => get_current_user_id(),
            'update_date_gmt'                       => false,
            'update_user_id'                        => false,
        ) );

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

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

        $this->id                           = absint( $args['pimwick_rewards_offer_id'] );
        $this->title                        = $args['title'];
        $this->description                  = $args['description'];
        $this->coupon_amount                = $args['coupon_amount'];
        $this->points                       = $args['points'];
        $this->free_shipping                = boolval( $args['free_shipping'] );
        $this->individual_use               = boolval( $args['individual_use'] );
        $this->exclude_sale_items           = boolval( $args['exclude_sale_items'] );
        $this->menu_order                   = absint( $args['menu_order'] );
        $this->status                       = $args['status'];
        $this->create_date_gmt              = $args['create_date_gmt'];
        $this->create_user_id               = $args['create_user_id'];
        $this->update_date_gmt              = $args['update_date_gmt'];
        $this->update_user_id               = $args['update_user_id'];
    }

    /* Getters */
    public function get_id( $context = 'view' ) {
        return $this->id;
    }

    public function get_title( $context = 'view' ) {
        if ( $context == 'edit' ) {
            return $this->title;
        }

        return pwlpar_format_string( $this->title );
    }

    public function get_description( $context = 'view' ) {
        if ( $context == 'edit' ) {
            return $this->description;
        }

        return pwlpar_format_string( $this->description );
    }

    public function get_coupon_type( $context = 'view' ) {
        if ( $context == 'edit' ) {
            return 'fixed_cart';
        }

        return pwlpar_get_offer_coupon_type_name( 'fixed_cart' );
    }

    public function get_coupon_amount( $context = 'view' ) {
        if ( $context == 'edit' ) {
            return $this->coupon_amount;
        }

        return wc_price( $this->coupon_amount );
    }

    public function get_points( $context = 'view' ) {
        if ( $context == 'edit' ) {
            return $this->points;
        }

        return pwlpar_format_points( $this->points );
    }

    public function get_free_shipping( $context = 'view' ) {
        return $this->free_shipping;
    }

    public function get_individual_use( $context = 'view' ) {
        return $this->individual_use;
    }

    public function get_exclude_sale_items( $context = 'view' ) {
        return $this->exclude_sale_items;
    }

    public function get_image_url( $context = 'view' ) {
        return pwlpar_offer_logo_url_default();
    }

    public function get_menu_order( $context = 'view' ) {
        return $this->menu_order;
    }

    public function get_status( $context = 'view' ) {
        return $this->status;
    }

    public function get_create_date( $context = 'view' ) {
        if ( $context == 'edit' ) {
            return $this->create_date_gmt;
        }

        return pwlpar_format_datetime( $this->create_date_gmt );
    }

    public function get_create_user_id( $context = 'view' ) {
        return $this->create_user_id;
    }

    public function get_update_date( $context = 'view' ) {
        if ( $context == 'edit' ) {
            return $this->update_date_gmt;
        }

        return pwlpar_format_datetime( $this->update_date_gmt );
    }

    public function get_update_user_id( $context = 'view' ) {
        return $this->update_user_id;
    }

    public function get_product_ids( $context = 'view' ) {
        $restrictions = $this->get_restrictions();
        if ( isset( $restrictions['product_id'] ) ) {
            return $restrictions['product_id'];
        } else {
            return array();
        }
    }

    public function get_excluded_product_ids( $context = 'view' ) {
        $restrictions = $this->get_restrictions();
        if ( isset( $restrictions['excluded_product_id'] ) ) {
            return $restrictions['excluded_product_id'];
        } else {
            return array();
        }
    }

    public function get_product_categories( $context = 'view' ) {
        $restrictions = $this->get_restrictions();
        if ( isset( $restrictions['category_id'] ) ) {
            return $restrictions['category_id'];
        } else {
            return array();
        }
    }

    public function get_excluded_product_categories( $context = 'view' ) {
        $restrictions = $this->get_restrictions();
        if ( isset( $restrictions['excluded_category_id'] ) ) {
            return $restrictions['excluded_category_id'];
        } else {
            return array();
        }
    }



    /* Setters */
    public function set_id( $id ) {
        $this->id = absint( $id );
    }

    public function set_title( $title ) {
        $this->title = $title;
    }

    public function set_description( $description ) {
        $this->description = $description;
    }

    public function set_coupon_amount( $coupon_amount ) {
        $this->coupon_amount = $coupon_amount;
    }

    public function set_points( $points ) {
        $this->points = $points;
    }

    public function set_free_shipping( $free_shipping ) {
        $this->free_shipping = boolval( $free_shipping );
    }

    public function set_individual_use( $individual_use ) {
        $this->individual_use = boolval( $individual_use );
    }

    public function set_exclude_sale_items( $exclude_sale_items ) {
        $this->exclude_sale_items = boolval( $exclude_sale_items );
    }

    public function set_menu_order( $menu_order ) {
        $this->menu_order = absint( $menu_order );
    }

    public function set_status( $status ) {
        $this->status = $status;
    }

    public function set_product_ids( $product_ids ) {
        $this->set_restrictions( 'product_id', $product_ids );
    }

    public function set_excluded_product_ids( $excluded_product_ids ) {
        $this->set_restrictions( 'excluded_product_id', $excluded_product_ids );
    }

    public function set_category_ids( $category_ids ) {
        $this->set_restrictions( 'category_id', $category_ids );
    }

    public function set_excluded_category_ids( $excluded_category_ids ) {
        $this->set_restrictions( 'excluded_category_id', $excluded_category_ids );
    }



    /* Public methods */
    public function save() {
        global $wpdb, $pwlpardb;

        $data = array(
            'coupon_amount' => $this->coupon_amount,
            'points' => $this->points,
            'title' => $this->title,
            'description' => $this->description,
            'free_shipping' => $this->free_shipping,
            'individual_use' => $this->individual_use,
            'exclude_sale_items' => $this->exclude_sale_items,
            'menu_order' => $this->menu_order,
            'status' => $this->status,
        );

        if ( empty( $this->id ) ) {
            $data['create_date_gmt'] = current_time( 'mysql', true );
            $data['create_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
            $wpdb->insert( $pwlpardb->offer, $data ); //db call ok

            if ( $wpdb->last_error ) {
                return false;
            }
            $this->set_id( $wpdb->insert_id );

        } else {
            $data['update_date_gmt'] = current_time( 'mysql', true );
            $data['update_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
            $wpdb->update( $pwlpardb->offer, $data, array( 'pimwick_rewards_offer_id' => $this->id ) ); //db call ok
            if ( $wpdb->last_error ) {
                return false;
            }
        }

        $this->save_restrictions();

        return $this->id;
    }

    public function delete( $permanent = false ) {
        global $wpdb, $pwlpardb;

        do_action( 'pwlpar_offer_delete', $this, $permanent );

        if ( empty( $this->id ) ) {
            return false;
        }

        if ( $permanent ) {
            // Using a custom table, not a WordPress table, so this warning can be ignored.
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $result = $wpdb->delete( $pwlpardb->offer, array( 'pimwick_rewards_offer_id' => $this->id ) ); //db call ok
        } else {
            $this->set_status( 'trash' );
            $this->save();
            $result = true;
        }

        do_action( 'pwlpar_offer_deleted', $this, $permanent );

        return $result;
    }

    public function restore() {
        $this->set_status( 'draft' );
        return true;
    }

    public function get_button_title() {
        $points = $this->get_points();
        if ( empty( $points ) ) {
            $points = pwlpar_free_label();
        }

        if ( is_admin() ) {
            $points = '<span class="pwlpara-offer-button-points">' . $points  . '</span>';
        }

        /* translators: %s is cost in points to claim this offer. */
        $button_title = sprintf( esc_html__( 'Claim for %s', 'pw-loyalty-points-and-rewards-for-woocommerce' ), $points );
        return apply_filters( 'pwlpar_offer_get_button_title', $button_title, $this );
    }

    public function is_active() {
        $active = ( $this->status == 'publish' );

        return apply_filters( 'pwlpar_offer_is_active', $active, $this );
    }

    public function get_claim_url() {
        $url = add_query_arg( array(
            'pwlpar_action' => 'claim_offer',
            'offer_id' => $this->id,
        ), pwlpar_get_home_url() );

        return apply_filters( 'pwlpar_offer_get_claim_url', $url, $this );
    }

    public function get_edit_url() {
        return pwlpar_get_offer_edit_url( $this->get_id() );
    }

    public function get_redeemed_count() {
        return $this->get_statistics()->redeemed;
    }

    public function get_claimed_count() {
        return $this->get_statistics()->claimed;
    }

    public function get_user_can_claim_offer( $user_id = false ) {
        // When in preview / admin mode, the offer can be "claimed".
        if ( is_admin() ) {
            return true;
        }

        if ( empty( $user_id ) ) {
            $user_id = get_current_user_id();
        }

        $can_claim = true;

        $balance = pwlpar_current_user_point_balance();
        $points = $this->get_points( 'edit' );

        // Check their balance.
        if ( $balance < $points ) {
            $can_claim = __( 'Not enough points to claim this offer.', 'pw-loyalty-points-and-rewards-for-woocommerce' );
        }

        return apply_filters( 'pwlpar_user_can_claim_offer', $can_claim, $this );
    }



    /* Private functions */
    private function get_statistics() {
        global $wpdb, $pwlpardb;

        if ( is_null( $this->statistics_cache ) ) {
            // Using a custom table, not a WordPress table, so this warning can be ignored.
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $results = $wpdb->get_results( $wpdb->prepare( "
                SELECT
                    COUNT(CASE WHEN r.status = 'pending' THEN 1 END) AS redeemed,
                    COUNT(CASE WHEN r.status = 'claimed' THEN 1 END) AS claimed
                FROM
                    %i AS r
                WHERE
                    r.pimwick_rewards_offer_id = %d
                ",
                $pwlpardb->reward,
                $this->id
            ) );

            $this->statistics_cache = $results[0];
        }

        return $this->statistics_cache;
    }

    private function get_restrictions() {
        global $wpdb, $pwlpardb;

        if ( is_null( $this->restrictions_cache ) ) {
            $this->restrictions_cache = array();

            // Using a custom table, not a WordPress table, so this warning can be ignored.
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $results = $wpdb->get_results( $wpdb->prepare( "
                SELECT
                    r.type,
                    r.object_id
                FROM
                    %i AS r
                WHERE
                    r.pimwick_rewards_offer_id = %d
                ",
                $pwlpardb->offer_restriction,
                $this->id
            ) );

            foreach ( $results as $result ) {
                $this->restrictions_cache[ $result->type ][] = $result->object_id;
            }
        }

        return $this->restrictions_cache;
    }

    private function set_restrictions( $type, $ids ) {
        $restrictions = $this->get_restrictions();
        $restrictions[ $type ] = $ids;
        $this->restrictions_cache = $restrictions;
    }

    private function save_restrictions() {
        global $wpdb, $pwlpardb;

        if ( is_null( $this->restrictions_cache ) || !is_array( $this->restrictions_cache ) ) {
            return;
        }

        foreach ( $this->restrictions_cache as $type => $ids ) {
            // Using a custom table, not a WordPress table, so this warning can be ignored.
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->delete( $pwlpardb->offer_restriction, array( 'pimwick_rewards_offer_id' => $this->id, 'type' => $type ) ); //db call ok
            foreach ( $ids as $id ) {
                // Using a custom table, not a WordPress table, so this warning can be ignored.
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
                $wpdb->insert( $pwlpardb->offer_restriction, array(
                    'pimwick_rewards_offer_id' => $this->id,
                    'type' => $type,
                    'object_id' => $id,
                ) );
            }
        }
    }
}
