<?php
/**
 * API frontend endpoints class.
 *
 * @package SaveToWishlist\Classes\API
 * @since 1.0.0
 */
namespace SaveToWishlist\Classes\API;

use SaveToWishlist\Abstracts\Singleton;
use SaveToWishlist\Classes\Frontend\Wishlist;
use SaveToWishlist\Classes\Factories\Collections;
use SaveToWishlist\Classes\Factories\Collection_Item;

/**
 * Class API Frontend Endpoints
 *
 * This class creates an API for the plugin.
 */
class API_Frontend_Endpoints extends Singleton {
    use \SaveToWishlist\Traits\API_Permissions;

    /**
     * The API namespace.
     *
     * @since 1.0.0
     * @access private
     * @var string
     */
    private $api_namespace = 'saveto-wishlist/v1';

    /**
     * Base route.
     *
     * @since 1.0.0
     * @access private
     * @var string
     */
    private $base = 'frontend/endpoints';

    /**
     * Run the application.
     *
     * @since 1.0.0
     * @access public
     */
    public function run() {
        // Register the API.
        add_action( 'rest_api_init', array( $this, 'register_api' ) );
    }

    /**
     * Register the API.
     */
    public function register_api() {
        \register_rest_route(
            $this->api_namespace,
            '/' . $this->base,
            array(
                'methods'             => 'POST',
                'callback'            => array( $this, 'save_to_wishlist' ),
                'permission_callback' => array( $this, 'check_user_permission' ),
            )
        );

        \register_rest_route(
            $this->api_namespace,
            '/' . $this->base . '/wishlists',
            array(
                'methods'             => 'GET',
                'callback'            => array( $this, 'get_wishlists' ),
                'permission_callback' => array( $this, 'check_user_permission' ),
            )
        );

        \register_rest_route(
            $this->api_namespace,
            '/' . $this->base . '/wishlist-items',
            array(
                'methods'             => 'GET',
                'callback'            => array( $this, 'get_wishlist_items' ),
                'permission_callback' => array( $this, 'check_any_user_has_permission' ),
            )
        );

        \register_rest_route(
            $this->api_namespace,
            '/' . $this->base . '/guest-wishlist-products',
            array(
                'methods'             => 'POST',
                'callback'            => array( $this, 'get_guest_wishlist_products' ),
                'permission_callback' => array( $this, 'check_guest_permission' ),
            )
        );
    }

    /**
     * Save to wishlist.
     *
     * @param \WP_REST_Request $request Full details about the request.
     *
     * @since 1.0.0
     * @access public
     *
     * @return array
     */
    public function save_to_wishlist( $request ) {
        $action = $request->get_param( 'action' );

        $message = __( 'Wishlist created successfully.', 'saveto-wishlist-lite-for-woocommerce' );
        $skipped = array();

        if ( 'add_wishlist' === $action || 'update_wishlist' === $action ) {
            $id                  = (int) $request->get_param( 'id' ) ?? 0;
            $name                = sanitize_text_field( $request->get_param( 'name' ) ) ?? '';
            $description         = sanitize_textarea_field( $request->get_param( 'description' ) ) ?? '';
            $status              = sanitize_text_field( $request->get_param( 'status' ) ) ?? 'publish';
            $is_default          = (int) $request->get_param( 'is_default' ) ?? 0;
            $is_public           = (int) $request->get_param( 'is_public' ) ?? 0;
            $url_code            = sanitize_text_field( $request->get_param( 'url_code' ) ) ?? '';
            $user_id             = (int) $request->get_param( 'user_id' ) ?? 0;
            $emails              = array_filter(
                array_map( 'sanitize_email', $request->get_param( 'emails' ) ?? array() ),
                function ( $value ) {
                    return is_email( $value );
                }
            );
            $user_ids            = array_filter(
                array_map( 'intval', $request->get_param( 'user_ids' ) ?? array() ),
                function ( $value ) {
                    return $value > 0;
                }
            );
            $allowed_roles       = array_map( 'sanitize_text_field', $request->get_param( 'allowed_roles' ) ?? array() );
            $allowed_edit_emails = array_map( 'sanitize_email', $request->get_param( 'allowed_edit_emails' ) ?? array() );
            $from_edit           = sanitize_text_field( $request->get_param( 'from_edit' ) ) ?? '';

            $data = array(
                'id'                  => $id,
                'name'                => $name,
                'description'         => $description,
                'status'              => $status,
                'user_id'             => $user_id,
                'is_default'          => $is_default,
                'is_public'           => $is_public,
                'url_code'            => $url_code,
                'emails'              => $emails,
                'user_ids'            => $user_ids,
                'allowed_roles'       => $allowed_roles,
                'allowed_edit_emails' => $allowed_edit_emails,
                'from_edit'           => $from_edit,
            );

            if ( 'add_wishlist' === $action ) {
                $data['id'] = 0;

                do_action( 'stwlite_before_api_save_collection_add_wishlist', $data );
            } else {
                // filter to remove from the array if not in params.
                $data = array_filter(
                    $data,
                    function ( $key ) use ( $request ) {
                        return in_array( $key, array_keys( $request->get_params() ), true );
                    },
                    ARRAY_FILTER_USE_KEY
                );

                do_action( 'stwlite_before_api_save_collection_update_wishlist', $data );

                $message = __( 'Wishlist updated successfully.', 'saveto-wishlist-lite-for-woocommerce' );
            }

            Collections::instance()->save_collection( $data );
        } elseif ( 'remove_wishlist' === $action ) {
            $ids = $request->get_param( 'ids' );

            // Enforce ownership for non-admin callers. The route's
            // permission_callback only requires is_user_logged_in(); without
            // this filter any authenticated user could delete another
            // customer's wishlist by ID.
            if ( ! current_user_can( 'manage_options' ) ) {
                $ids = Collections::instance()->filter_ids_owned_by_user( $ids, get_current_user_id() );

                if ( empty( $ids ) ) {
                    return array(
                        'status'  => 'error',
                        'message' => __( 'You are not allowed to delete these wishlists.', 'saveto-wishlist-lite-for-woocommerce' ),
                        'skipped' => array(),
                    );
                }
            }

            $deleted = Collections::instance()->delete_collections( $ids );
            $skipped = Collections::instance()->get_skipped_last_wishlist_ids();

            if ( ! empty( $skipped ) && 0 === (int) $deleted ) {
                $message = _n(
                    'This wishlist cannot be deleted because it is your only wishlist and would be recreated automatically.',
                    'These wishlists cannot be deleted because each is the owner\'s only wishlist and would be recreated automatically.',
                    count( $skipped ),
                    'saveto-wishlist-lite-for-woocommerce'
                );
            } elseif ( ! empty( $skipped ) ) {
                $message = __( 'Some wishlists were skipped because they are the only wishlist for their owner.', 'saveto-wishlist-lite-for-woocommerce' );
            } else {
                $message = __( 'Wishlist deleted successfully.', 'saveto-wishlist-lite-for-woocommerce' );
            }
        } elseif ( 'add_wishlist_item' === $action || 'update_wishlist_item' === $action ) {
            $id            = $request->get_param( 'id' ) ?? 0;
            $collection_id = $request->get_param( 'collection_id' ) ?? 0;
            $product_id    = $request->get_param( 'product_id' ) ?? 0;
            $variation_id  = $request->get_param( 'variation_id' ) ?? 0;
            $quantity      = $request->get_param( 'quantity' ) ?? 0;
            $priority      = $request->get_param( 'priority' ) ?? 0;
            $notes         = $request->get_param( 'notes' ) ?? '';

            $data = array(
                'id'            => $id,
                'collection_id' => $collection_id,
                'product_id'    => $product_id,
                'variation_id'  => $variation_id,
                'quantity'      => $quantity,
                'priority'      => $priority,
                'notes'         => $notes,
            );

            if ( 'add_wishlist_item' === $action ) {
                $data['id'] = 0;

                do_action( 'stwlite_before_api_save_collection_item_add_wishlist_item', $data );

                $message = __( 'Wishlist item added successfully.', 'saveto-wishlist-lite-for-woocommerce' );
            } else {
                // filter to remove from the array if not in params.
                $data = array_filter(
                    $data,
                    function ( $key ) use ( $request ) {
                        return in_array( $key, array_keys( $request->get_params() ), true );
                    },
                    ARRAY_FILTER_USE_KEY
                );

                do_action( 'stwlite_before_api_save_collection_item_update_wishlist_item', $data );

                $message = __( 'Wishlist item updated successfully.', 'saveto-wishlist-lite-for-woocommerce' );
            }

            Collections::instance()->save_collection_item( $data );
        } elseif ( 'move_wishlist_item' === $action ) {
            $id            = $request->get_param( 'id' ) ?? 0;
            $collection_id = $request->get_param( 'collection_id' ) ?? 0;

            $data = array(
                'id'            => (int) $id,
                'collection_id' => (int) $collection_id,
            );

            do_action( 'stwlite_before_api_save_collection_item_move_wishlist_item', $data );

            $message = __( 'Wishlist item moved successfully.', 'saveto-wishlist-lite-for-woocommerce' );

            Collections::instance()->move_collection_item( $data );
        } elseif ( 'remove_wishlist_item' === $action ) {
            $collection_id = (int) $request->get_param( 'collection_id' );
            $product_id    = (int) $request->get_param( 'product_id' );
            $variation_id  = (int) $request->get_param( 'variation_id' );

            $variation_ids = array();
            if ( 0 !== $variation_id ) {
                $variation_ids[] = $variation_id;
            }

            Collections::instance()->delete_collection_items( $collection_id, array( $product_id ), false, $variation_ids );

            $message = __( 'Wishlist item deleted successfully.', 'saveto-wishlist-lite-for-woocommerce' );
        } elseif ( 'update_wishlist_item_position' === $action ) {
            $lists = $request->get_param( 'lists' );

            Collections::instance()->update_wishlist_item_position( $lists );

            $message = __( 'Wishlist item position updated successfully.', 'saveto-wishlist-lite-for-woocommerce' );
        }

        return array(
            'status'  => 'success',
            'message' => $message,
            'skipped' => array_map( 'intval', $skipped ),
        );
    }

    /**
     * Get wishlists.
     *
     * @param \WP_REST_Request $request Full details about the request.
     *
     * @since 1.0.0
     * @access public
     *
     * @return array
     */
    public function get_wishlists( $request ) {
        $params = $request->get_params();

        // Filter to show all wishlists for admin.
        $show_for_admin = apply_filters( 'stwlite_show_all_wishlists_for_admin', false );

        // Check if the user is admin by checking the user role.
        $user = wp_get_current_user();
        if ( in_array( 'administrator', $user->roles, true ) && $show_for_admin ) {
            // Unset the user_id parameter.
            unset( $params['user_id'] );
        }

        $wishlists = Wishlist::instance()->get_wishlists( $params );

        return rest_ensure_response( $wishlists );
    }

    /**
     * Get wishlist items.
     *
     * @param \WP_REST_Request $request Full details about the request.
     *
     * @since 1.0.0
     * @access public
     *
     * @return array
     */
    public function get_wishlist_items( $request ) {
        $params = $request->get_params();

        $wishlist_items = Wishlist::instance()->get_wishlist_items( $params );

        return rest_ensure_response( $wishlist_items );
    }

    /**
     * Delete wishlist.
     *
     * @param \WP_REST_Request $request Full details about the request.
     *
     * @since 1.0.0
     * @access public
     *
     * @return array
     */
    public function delete_wishlist( $request ) {
        $params = $request->get_params();

        $ids      = $params['ids'];
        $wishlist = Collections::instance()->delete_collections( $ids );

        return rest_ensure_response( $wishlist );
    }

    /**
     * Delete wishlist item.
     *
     * @param \WP_REST_Request $request Full details about the request.
     *
     * @since 1.0.0
     * @access public
     *
     * @return array
     */
    public function delete_wishlist_item( $request ) {
        $params = $request->get_params();

        $collection_id = $params['collection_id'];
        $product_id    = $params['product_id'];

        $wishlist_item = Collections::instance()->delete_collection_items( $collection_id, array( $product_id ), false );

        return rest_ensure_response( $wishlist_item );
    }

    /**
     * Update wishlist item.
     *
     * @param \WP_REST_Request $request Full details about the request.
     *
     * @since 1.0.0
     * @access public
     *
     * @return array
     */
    public function update_wishlist_item( $request ) {
        $item_id = $request->get_param( 'id' );
        $data    = $request->get_param( 'data' );

        $wishlist_item = Wishlist::instance()->update_wishlist_item( $item_id, $data );

        return rest_ensure_response( $wishlist_item );
    }

    /**
     * Get guest wishlist products.
     *
     * @param \WP_REST_Request $request Full details about the request.
     *
     * @since 1.0.0
     * @access public
     *
     * @return array
     */
    public function get_guest_wishlist_products( $request ) {
        $product_data = $request->get_param( 'products' );

        $products = array();
        foreach ( $product_data as $product ) {
            $product_id     = (int) $product['productId'];
            $product_object = wc_get_product( $product_id );

            if ( ! $product_object || ! $product_object->exists() ) {
                continue;
            }

            $product_obj             = new \stdClass();
            $product_obj->id         = $product_id;
            $product_obj->product_id = $product_object->get_id();
            $product_obj->quantity   = (int) $product['quantity'];
            $product_obj->priority   = isset( $product['priority'] ) ? (int) $product['priority'] : 0;
            $product_obj->added_at   = $product['addedAt'];

            $products[] = $product_obj;
        }

        $products = array_map(
            function ( $product ) {
                return Collection_Item::get_instance( $product );
            },
            $products
        );

        // Filter the product.
        $products = apply_filters( 'stwlite_guest_wishlist_products_data', $products, $product_data );

        return rest_ensure_response( $products );
    }
}
