<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}

class CGC_Rest_API {

    public function __construct() {
        add_action( 'rest_api_init', array( $this, 'register_routes' ) );


    }

    // Shared by every route below that only needs "is this a same-site
    // request with a valid wp_rest nonce" rather than a full capability
    // check - reads the nonce header the same safe way core's own
    // rest_cookie_check_errors() does (unslash + sanitize before use).
    private function verify_rest_nonce() {
        $nonce = isset( $_SERVER['HTTP_X_WP_NONCE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_WP_NONCE'] ) ) : '';

        if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
            header( 'HTTP/1.0 403 Forbidden' );
            exit;
        }
    }

    public function register_routes() {
        register_rest_route( 'cgc/v2', '/save_template', array(
            'methods' => 'POST',
            'callback' => array( $this, 'save_template' ),
            'permission_callback' => function ( $request ) {
                return true;
            }
        ) );

        // Admin-only "packaging" workflow (locks a batch of designs and
        // emails a notification) - was fully public, letting any visitor
        // lock arbitrary post IDs and trigger emails to a hardcoded
        // address. Its only caller (app/src/labels.tsx) isn't even part of
        // the current webpack build (see app/webpack.config.js's commented-
        // out 'label-list' entry), but the route itself still exists, so it
        // still needs real authorization rather than just a nonce check.
        register_rest_route( 'cgc/v2', '/save_templates', array(
            'methods' => 'POST',
            'callback' => array( $this, 'save_templates' ),
            'permission_callback' => function ( $request ) {
                return current_user_can( 'manage_options' );
            }
        ) );


        //delete_template
        register_rest_route( 'cgc/v2', '/delete_template', array(
            'methods' => 'POST',
            'callback' => array( $this, 'delete_template' ),
            'permission_callback' => function ( $request ) {
                return true;
            }
        ) );


        //create a gift card and add it to the woo cart.
        /* register_rest_route( 'cgc/v2', '/add_to_cart', array(
            'methods' => 'POST',
            'callback' => array( $this, 'add_to_cart' ),
            'permission_callback' => function ( $request ) {
                return true;
            }
        ) ); */


        //add media to the media library
        register_rest_route( 'cgc/v2', '/add_media', array(
            'methods' => 'POST',
            'callback' => array( $this, 'add_media' ),
            'permission_callback' => function ( $request ) {
                return true;
            }
        ) );

        //generate_attachment_meta
        register_rest_route( 'cgc/v2', '/generate_attachment_meta', array(
            'methods' => 'POST',
            'callback' => array( $this, 'generate_attachment_meta' ),
            'permission_callback' => function ( $request ) {
                return is_user_logged_in();
            }
        ) );

        //list all cgc-design posts (starters + custom) for the block editor's design picker
        register_rest_route( 'cgc/v2', '/designs', array(
            'methods' => 'GET',
            'callback' => array( $this, 'list_designs' ),
            'permission_callback' => function ( $request ) {
                // Site-builder audience only (this feeds the block/widget
                // editor's design picker) - is_user_logged_in() alone let
                // any authenticated account (eg. a self-registered
                // WooCommerce customer) call this. get_all_designs() itself
                // is now also scoped to post_parent = 0 as a second,
                // independent layer excluding personalized customer designs
                // regardless of caller.
                return current_user_can( 'edit_posts' );
            }
        ) );

        //search/list WooCommerce products for the block editor's "Products" field picker
        register_rest_route( 'cgc/v2', '/products', array(
            'methods' => 'GET',
            'callback' => array( $this, 'list_products' ),
            'permission_callback' => function ( $request ) {
                // Same site-builder-only audience as /designs above.
                return current_user_can( 'edit_posts' );
            }
        ) );

        // Called by the thank-you-page-only re-render bootstrap (see
        // class-cgc-woocommerce.php's maybe_enqueue_rerender()) once a
        // {coupon_code}/{expire_date} design has been re-substituted with
        // real values client-side. Guarded by a dedicated one-time token
        // (not just the general wp_rest nonce) since a card_id alone is a
        // guessable sequential ID and this has a real side effect on a live
        // attachment file - see finalize_card_render().
        register_rest_route( 'cgc/v2', '/finalize_card_render', array(
            'methods' => 'POST',
            'callback' => array( $this, 'finalize_card_render' ),
            'permission_callback' => function ( $request ) {
                return true;
            }
        ) );

    }

    public function list_designs( WP_REST_Request $request ) {
        global $cgc_fetch;
        if ( ! $cgc_fetch ) {
            return rest_ensure_response( array() );
        }
        return rest_ensure_response( $cgc_fetch->get_all_designs() );
    }

    public function list_products( WP_REST_Request $request ) {
        global $cgc_fetch;
        if ( ! $cgc_fetch ) {
            return rest_ensure_response( array() );
        }
        $search = $request->get_param( 'search' ) ?? '';
        return rest_ensure_response( $cgc_fetch->get_products_summary( $search ) );
    }

    public function save_templates( WP_REST_Request $request ) {
        $this->verify_rest_nonce();

        $data = $request->get_json_params();

        $post_id = absint(  $data['id'] );

        $cards = isset($data['packages']) ? $data['packages'] : 1;


        update_post_meta( $post_id, '_cgc_locked', true );


        $admin_email = 'crutenberg@gmail.com';

        //get all design ids with this post as their parent
        $args = array(
            'post_type' => 'cgc-design',
            'post_status' => 'any',
            'post_parent' => $post_id,
            'fields' => 'ids'
        );

        $design_ids = get_posts($args);

        //paths 
        $paths = [];

        foreach ($design_ids as $design_id) {
            //get the paths of the featured iages
            $featured_image_id = get_post_thumbnail_id($design_id);
            $featured_image_path = get_attached_file($featured_image_id);
            if ($featured_image_path) {
                $paths[] = $featured_image_path;
            }
        }


        $to = $admin_email;
        $subject = 'Designs Ready for Packaging';
        $body = 'These designs are ready to be packaged. We need to send out ' . $cards . ' number of packages.';

        $headers = array('Content-Type: text/html; charset=UTF-8');

        wp_mail($to, $subject, $body, $headers, $paths);


        return rest_ensure_response( array( 'success' => true ) );

    }

    public function delete_template(  WP_REST_Request $request ) {
        $this->verify_rest_nonce();

        $data = $request->get_json_params();

        $post_id = absint(  $data['card_id'] );

        if( ! $post_id ) {
            return new WP_Error( 'rest_missing_template', esc_html__( 'Missing template data.', 'gift-card-studio' ), array( 'status' => 400 ) );
        }

        // Only the admin design-editor's own "Delete" button calls this
        // (see app/src/parts/canvas.tsx) - the nonce check above isn't
        // enough on its own since a logged-out visitor gets a valid
        // wp_rest nonce too, and without this check, any caller with one
        // could force-delete an arbitrary post of ANY type by ID.
        if ( 'cgc-design' !== get_post_type( $post_id ) || ! current_user_can( 'delete_post', $post_id ) ) {
            return new WP_Error( 'rest_forbidden', esc_html__( 'You are not allowed to delete this design.', 'gift-card-studio' ), array( 'status' => 403 ) );
        }

        wp_delete_post( $post_id, true );

        return rest_ensure_response( array( 'success' => true ) );

    }

    public function add_media( WP_REST_Request $request ) {
        $this->verify_rest_nonce();
        $user_id = get_current_user_id();

       /*  if ( ! $user_id ) {
            return new WP_Error( 'rest_forbidden', esc_html__( 'You are not allowed to save a template.', 'gift-card-studio' ), array( 'status' => 401 ) );
        } */


        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- the file itself is validated below by wp_handle_upload()'s real content/mime check, not by this array access.
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- verify_rest_nonce() above already checks the request nonce; PHPCS's sniff doesn't recognize this shared wrapper method as a nonce-verification call, only direct wp_verify_nonce()/check_ajax_referer() calls.
        $file = $_FILES['file'] ?? null;

        if(  ! $file ) {
            return new WP_Error( 'rest_missing_image', esc_html__( 'Missing image data.', 'gift-card-studio' ), array( 'status' => 400 ) );
        }

        // This route is reachable by anonymous guest checkouts (customer
        // image-upload fields), so it can't require login - instead the
        // file itself must be validated properly. The previous check only
        // looked at $file['type'] (the client-supplied Content-Type header)
        // and used the client-supplied filename's extension verbatim - both
        // fully attacker-controlled and trivially spoofable (eg. uploading
        // a PHP script named/labeled as a PNG would have been saved to the
        // uploads directory with a .php extension, a straight path to
        // remote code execution). wp_handle_upload() with a "mimes"
        // override instead validates the file's real content against its
        // extension (via wp_check_filetype_and_ext()), the same
        // battle-tested path core's own media uploader uses. SVG is
        // deliberately excluded - WordPress core doesn't allow it by
        // default because an SVG can carry an embedded <script> that
        // executes when viewed directly, a stored-XSS vector no MIME check
        // here would catch.
        require_once ABSPATH . 'wp-admin/includes/file.php';
        require_once ABSPATH . 'wp-admin/includes/image.php';

        $allowed_mimes = array(
            'jpg|jpeg|jpe' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif',
            'bmp' => 'image/bmp',
            'tif|tiff' => 'image/tiff',
            'ico' => 'image/x-icon',
            'webp' => 'image/webp',
        );

        $moved = wp_handle_upload( $file, array(
            'test_form' => false,
            'mimes' => $allowed_mimes,
        ) );

        if ( isset( $moved['error'] ) ) {
            return new WP_Error( 'rest_invalid_image_type', $moved['error'], array( 'status' => 400 ) );
        }

        $attachment = array(
            'post_mime_type' => $moved['type'],
            'post_title' => preg_replace('/\.[^.]+$/', '', basename($moved['file'])),
            'post_content' => '',
            'post_status' => 'inherit',
            'guid' => $moved['url'],
            'post_author' => $user_id
        );

        $attach_id = wp_insert_attachment($attachment, $moved['file']);


        $image_url = wp_get_attachment_url($attach_id);

        return rest_ensure_response( array( 'success' => true, 'id' => $attach_id, 'url' => $image_url ) );

    }

    public function find_gift_card_product() {
        $args = array(
            'post_type' => 'product',
            'posts_per_page' => 1,
            'meta_query' => array(
                array(
                    'key' => '_cgc_gift_card',
                    'value' => 'yes'
                )
            )
        );

        $posts = get_posts( $args );

        if( $posts ) {
            return $posts[0]->ID;
        }else{

            //create the product
            $product_args = [
                'post_title' => 'Gift Card',
                'post_content' => 'Gift Card',
                'post_status' => 'publish',
                'post_type' => 'product',
                //meta data
                'meta_input' => [
                    '_price' => 0,
                    '_regular_price' => 0,
                    '_sku' => 'gift-card',
                    '_cgc_gift_card' => 'yes',
                    //hide the product
                    '_visibility' => 'hidden',
                    '_stock_status' => 'instock',
                    '_manage_stock' => 'no',
                    
                ]            
            ];

            $product_id = wp_insert_post( $product_args );

            if( is_wp_error( $product_id ) ) {
                return new WP_Error( 'rest_cannot_add_to_cart', esc_html__( 'Could not create the gift card.', 'gift-card-studio' ), array( 'status' => 500 ) );
            }

            return $product_id;

        }

    }

    function check_prerequisites() {
    
        // var_dump(WC()->cart);
        
        if ( defined( 'WC_ABSPATH' ) ) {
            // WC 3.6+ - Cart and other frontend functions are not included for REST requests.
            include_once WC_ABSPATH . 'includes/wc-cart-functions.php';
            include_once WC_ABSPATH . 'includes/wc-notice-functions.php';
                    include_once WC_ABSPATH . 'includes/wc-template-hooks.php';
        }
    
        if ( null === WC()->session ) {
            $session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
    
            WC()->session = new $session_class();
            WC()->session->init();
        }
    
        if ( null === WC()->customer ) {
            WC()->customer = new WC_Customer( get_current_user_id(), true );
        }
    
        if ( null === WC()->cart ) {
            WC()->cart = new WC_Cart();
    
            WC()->cart->get_cart();
        }
    }

    public function add_to_cart( $data, $design_json = null, $design_width = 0, $design_height = 0 ) {

        //make sure woo is active
        if( ! class_exists( 'WooCommerce' ) ) {
            return new WP_Error( 'rest_no_woo', esc_html__( 'WooCommerce is not active.', 'gift-card-studio' ), array( 'status' => 400 ) );
        }

        $user_id = get_current_user_id();



        //if there

        $gift_card_ID = $this->find_gift_card_product();
        if( ! $gift_card_ID ) return;

        $product = wc_get_product( $gift_card_ID );

        //save the data
        $post_content = base64_encode(serialize( $data ) );

        $honoree = $data['recipient_name'] ?? $data['honor'] ?? '';

        $password = wp_generate_password();

        //create the custom-gift-card post
        $post_id = wp_insert_post( array(
            'post_title' => $honoree . ' - Gift Card',
            'post_name' => uniqid(),
            'post_content' => $post_content,
            'post_status' => 'publish',
            'post_author' => $user_id,
            'post_type' => 'custom-gift-card',
            'post_password' => $password,

        ) );

        //enddate - configurable via the GiftCard Studio settings page (defaults to 3 days)
        $expiration_days = CGC_Admin_Settings::get_coupon_expiration_days();
        $end_date = gmdate('Y-m-d H:i:s', strtotime("+{$expiration_days} days"));
        update_post_meta($post_id, '_cgc_end_date', $end_date);

        // Whether the form that created this card had a recipient-email
        // field configured - if not, the buyer is shown the card directly
        // on the order thank-you page instead of it being emailed out.
        update_post_meta($post_id, '_cgc_has_email_field', ! empty($data['hasEmailField']));
        if( ! empty($data['attachID']) ) {
            update_post_meta($post_id, '_cgc_attach_id', absint($data['attachID']));
        }

        // A design can reference {coupon_code}/{expire_date} tokens, which
        // can only resolve to a real value AFTER payment completes (see
        // class-cgc-woocommerce.php's maybe_generate_coupon()/
        // maybe_enqueue_rerender()) - unresolved tokens are left as literal
        // text by the canvas's substitution effect, so they're still
        // present verbatim in $design_json at this point if used.
        $design_json_string = $design_json ? wp_json_encode( $design_json ) : '';
        $uses_coupon_token = false !== strpos( $design_json_string, '{coupon_code}' );
        $uses_expire_token = false !== strpos( $design_json_string, '{expire_date}' );
        $needs_rerender = $uses_coupon_token || $uses_expire_token;

        update_post_meta( $post_id, '_cgc_uses_coupon_token', $uses_coupon_token );
        update_post_meta( $post_id, '_cgc_needs_rerender', $needs_rerender );

        if ( $needs_rerender ) {
            // Stored on THIS post rather than read back from the shared
            // cgc-design post later - that shared post gets overwritten (and
            // its old featured image deleted) by every subsequent purchase
            // of the same starter template, so it can't be trusted to still
            // hold what this specific customer saw by the time a deferred
            // re-render runs.
            update_post_meta( $post_id, '_cgc_design_json', $design_json );
            update_post_meta( $post_id, '_cgc_canvas_width', (int) $design_width );
            update_post_meta( $post_id, '_cgc_canvas_height', (int) $design_height );
        }

        if( is_wp_error( $post_id ) ) {
            return new WP_Error( 'rest_cannot_add_to_cart', esc_html__( 'Could not create the gift card.', 'gift-card-studio' ), array( 'status' => 500 ) );
        }

        $this->check_prerequisites();

        $price = (float) ( $data['amount'] ?? 0 );

        // The products field is a Pro feature - render_form() already
        // downgrades a products-type field to text for non-pro sites (see
        // class-cgc-blocks.php), so a real selectedProduct should never
        // reach here on a free site. Defense in depth against a directly
        // tampered request bypassing the form entirely.
        if ( ! empty( $data['selectedProduct'] ) && ! cgc_is_pro_active() ) {
            unset( $data['selectedProduct'] );
        }

        // If this submission was driven by a "Products" field, don't trust
        // the client-sent amount - re-resolve the authoritative price from
        // the actual product/variation server-side.
        $addon_meta = array();

        if ( ! empty( $data['selectedProduct']['id'] ) && function_exists( 'wc_get_product' ) ) {
            $parent_id = absint( $data['selectedProduct']['id'] );
            $selected_id = ! empty( $data['selectedProduct']['variationId'] )
                ? absint( $data['selectedProduct']['variationId'] )
                : $parent_id;

            $selected_product = wc_get_product( $selected_id );

            if ( $selected_product ) {
                $price = (float) wc_get_price_to_display( $selected_product );
            }

            // Re-validate/re-price WooCommerce Product Add-Ons selections
            // from the addon config itself, never from what the client
            // claims - same defense-in-depth principle as re-resolving
            // $price above rather than trusting $data['amount']. Percentage
            // deltas are always computed against this original base price,
            // not a running total - otherwise multiple percentage addons
            // would compound against each other instead of each being a
            // flat percentage of the product's own price.
            $base_price = $price;
            global $cgc_fetch;
            $addon_groups = $cgc_fetch ? $cgc_fetch->get_product_addons( $parent_id ) : array();
            $submitted_addons = (array) ( $data['selectedProduct']['addons'] ?? array() );

            foreach ( $addon_groups as $addon ) {
                $selection = $submitted_addons[ $addon['index'] ] ?? null;
                $is_empty = null === $selection || '' === $selection || ( is_array( $selection ) && ! $selection );

                if ( $addon['required'] && $is_empty ) {
                    return new WP_Error( 'rest_invalid_addons', esc_html__( 'Please complete all required options before continuing.', 'gift-card-studio' ), array( 'status' => 400 ) );
                }

                if ( $is_empty ) {
                    continue;
                }

                if ( in_array( $addon['type'], array( 'checkbox', 'radio', 'select' ), true ) ) {
                    $selected_indexes = is_array( $selection ) ? $selection : array( $selection );
                    $labels = array();

                    foreach ( $selected_indexes as $option_index ) {
                        $option = $addon['options'][ absint( $option_index ) ] ?? null;
                        if ( ! $option ) {
                            continue;
                        }
                        $price += 'percentage' === $option['price_type'] ? ( $option['price'] / 100 ) * $base_price : $option['price'];
                        $labels[] = $option['label'];
                    }

                    if ( $labels ) {
                        $addon_meta[ $addon['name'] ] = implode( ', ', $labels );
                    }
                } else { // text / textarea
                    $text = sanitize_textarea_field( (string) $selection );
                    if ( $addon['price'] ) {
                        $price += 'percentage' === $addon['price_type'] ? ( $addon['price'] / 100 ) * $base_price : $addon['price'];
                    }
                    $addon_meta[ $addon['name'] ] = $text;
                }
            }
        } else {
            // Plain "Amount" field submission (no Products field involved) -
            // unlike the branch above, there's no trusted server-side price
            // to re-derive this from: this request carries only the
            // submitted value, not a reference back to which page/field
            // configuration produced it, so it can't be cross-checked
            // against that field's actual configured pill options here.
            // Enforcing a site-wide floor is the defense-in-depth backstop
            // that closes a direct REST call submitting an arbitrary
            // (including near-zero or negative) amount, regardless of what
            // the field's own UI would have allowed.
            $minimum_amount = CGC_Admin_Settings::get_minimum_amount();
            if ( $price < $minimum_amount ) {
                return new WP_Error( 'rest_invalid_amount', esc_html__( 'The gift card amount is below the minimum allowed.', 'gift-card-studio' ), array( 'status' => 400 ) );
            }
        }

        // Reserved internal keys - never let a site owner's addon group
        // name collide with (and overwrite) the plugin's own order-item
        // bookkeeping meta (see CGC_Woocommerce::copy_cart_item_data_to_order_item()).
        $addon_meta = array_diff_key( $addon_meta, array_flip( array( 'card_id', 'title', 'password' ) ) );

        $cart_item_data = array(
            'custom_price' => $price,
            'title' => 'Gift Card in honor of - ' . $honoree,
            'password' => $password,
            'card_id' => $post_id,
        );

        if ( $addon_meta ) {
            $cart_item_data['addon_meta'] = $addon_meta;
        }

        $key = WC()->cart->add_to_cart( $gift_card_ID, 1, 0, array(), $cart_item_data );


        WC()->cart->calculate_totals();
        // Save cart to session
        WC()->cart->set_session();
        // Maybe set cart cookies
        WC()->cart->maybe_set_cart_cookies();

        $cart_url = wc_get_checkout_url();

        return rest_ensure_response( array( 'success' => true, 'cart_key' => $key, 'cart_url' => $cart_url, 'card_id' => $data['designID'], 'attach_id' => $data['attachID'] ) );
        
    }

    public function generate_attachment_meta( WP_REST_Request $request ) {
        $this->verify_rest_nonce();
        $attach_id  = intval( $request['attach_id'] );
        $file = get_attached_file( $attach_id );
        if( $attach_id ){
            

            //generate the thumbnail
            //generate small image
            //generate only thumbnail, not all sizes
            require_once(ABSPATH . 'wp-admin/includes/image.php');
            wp_generate_attachment_metadata($attach_id, $file);

        }
        return rest_ensure_response( array( 'success' => true, 'id' => $attach_id ) );
    }

    // Overwrites a gift card's already-uploaded attachment file in place
    // with a re-rendered PNG (real {coupon_code}/{expire_date} values now
    // substituted in) - called only by the thank-you-page-only bootstrap
    // enqueued by class-cgc-woocommerce.php's maybe_enqueue_rerender(),
    // after payment has completed. Guarded by a dedicated one-time token
    // rather than the general wp_rest nonce: a card_id alone is a guessable
    // sequential ID, and this endpoint has a real destructive side effect
    // (overwriting a live file) that must still work for guest checkouts.
    public function finalize_card_render( WP_REST_Request $request ) {
        $data = $request->get_json_params();

        $card_id = absint( $data['card_id'] ?? 0 );
        $token = sanitize_text_field( $data['rerender_token'] ?? '' );
        $image_data = $data['url'] ?? '';

        if ( ! $card_id || ! $token || ! $image_data ) {
            return new WP_Error( 'rest_missing_data', esc_html__( 'Missing card data.', 'gift-card-studio' ), array( 'status' => 400 ) );
        }

        if ( 'custom-gift-card' !== get_post_type( $card_id ) ) {
            return new WP_Error( 'rest_invalid_card', esc_html__( 'Invalid card.', 'gift-card-studio' ), array( 'status' => 404 ) );
        }

        $stored_token = get_post_meta( $card_id, '_cgc_rerender_token', true );
        $already_done = get_post_meta( $card_id, '_cgc_rerender_done', true );

        if ( $already_done || ! $stored_token || ! hash_equals( $stored_token, $token ) ) {
            return new WP_Error( 'rest_rerender_forbidden', esc_html__( 'This card has already been finalized or the token is invalid.', 'gift-card-studio' ), array( 'status' => 403 ) );
        }

        $attach_id = absint( get_post_meta( $card_id, '_cgc_attach_id', true ) );
        $file = $attach_id ? get_attached_file( $attach_id ) : '';

        if ( ! $attach_id || ! $file ) {
            return new WP_Error( 'rest_missing_attachment', esc_html__( 'No attachment to update.', 'gift-card-studio' ), array( 'status' => 404 ) );
        }

        $image_data = str_replace( 'data:image/png;base64,', '', $image_data );
        $image_data = str_replace( ' ', '+', $image_data );
        $decoded_image = base64_decode( $image_data );

        if ( ! $decoded_image ) {
            return new WP_Error( 'rest_invalid_image', esc_html__( 'Invalid image data.', 'gift-card-studio' ), array( 'status' => 400 ) );
        }

        file_put_contents( $file, $decoded_image );

        require_once ABSPATH . 'wp-admin/includes/image.php';
        wp_generate_attachment_metadata( $attach_id, $file );

        update_post_meta( $card_id, '_cgc_rerender_done', true );
        delete_post_meta( $card_id, '_cgc_rerender_token' );

        // The final image (real coupon code/expire date baked in) is only
        // ready as of this exact point - if this design has a recipient-
        // email field, this is what actually sends it (maybe_send_gift_card_email()
        // no-ops earlier for any design still waiting on this rerender).
        global $cgc_woocommerce;
        if ( $cgc_woocommerce ) {
            $cgc_woocommerce->maybe_send_gift_card_email( $card_id );
        }

        return rest_ensure_response( array( 'success' => true ) );
    }


    public function save_template( WP_REST_Request $request ) {
        $this->verify_rest_nonce();
        $user_id = get_current_user_id();
/* 
        if ( ! $user_id ) {
            return new WP_Error( 'rest_forbidden', esc_html__( 'You are not allowed to save a template.', 'gift-card-studio' ), array( 'status' => 401 ) );
        }  */

        $data = $request->get_json_params();

        if ( ! isset( $data['json'] ) ) {
            return new WP_Error( 'rest_missing_template', esc_html__( 'Missing template data.', 'gift-card-studio' ), array( 'status' => 400 ) );
        }

        $template = $data['json'];

        if( is_array( $template ) ) {
            $template = json_encode( $template );
        }
        $template = base64_encode(serialize( $template ));

        if ( ! $template ) {
            return new WP_Error( 'rest_missing_template', esc_html__( 'Missing template data.', 'gift-card-studio' ), array( 'status' => 400 ) );
        }

        $data_to_save = array(
            'post_title' => $data['name'] ?? 'Design #' . uniqid(),
            'post_excerpt' => $data['description'] ?? '',
            'post_content' => $template,
            'post_status' => 'draft',
            'post_author' => $user_id,
            'post_type' => 'cgc-design',
            'ping_status' => $data['starter']? 'open' : 'closed',
            'post_parent' => $data['parent'] ?? 0,
        );

        $action = $data['action'] ?? 'edit';

        if( 'edit' == $action ) {
            $card_id = absint( $data['card_id'] ?? 0 );

            // This REST route has no login requirement at all (guest
            // checkout must still work), so 'edit' - which overwrites an
            // EXISTING post in place, unlike 'create' which only ever
            // inserts a new one - must not be reachable by an
            // unauthenticated/unauthorized caller with an arbitrary
            // card_id. Guest checkout no longer sends 'edit' (see
            // gift-card-view.ts's submit(), which always sends 'create');
            // the only legitimate caller left is the site owner's own
            // design-editor "Save" action, which requires being logged in
            // with edit access to that specific post anyway.
            if ( ! $card_id || 'cgc-design' !== get_post_type( $card_id ) || ! current_user_can( 'edit_post', $card_id ) ) {
                return new WP_Error( 'rest_forbidden', esc_html__( 'You are not allowed to edit this design.', 'gift-card-studio' ), array( 'status' => 403 ) );
            }

            $data_to_save['ID'] = $card_id;

            //save the current post as a revision
            $revision = wp_save_post_revision( $card_id );

            $post_id = wp_update_post( $data_to_save );

            //get the feaurd image
            $attach_id = get_post_thumbnail_id( $card_id );

            //get the filename
            /* $filepath = get_attached_file( $attach_id );

            $filename = basename( $filepath );

            $has_attachment = file_exists( $filepath ) && 0 != $data['thumbnail'];

            if( ! $has_attachment ){
                $filename = uniqid() . '.png';
            } */
            if( $attach_id ) {
                //delete the old attachment
                wp_delete_attachment( $attach_id, true );
            }
        }else{
            $post_id = wp_insert_post( $data_to_save );

        }

        if( $data['type'] ) update_post_meta( $post_id, '_cgc_design_type', $data['type'] );
        if( $data['width'] ) update_post_meta( $post_id, '_cgc_canvas_width', $data['width'] );
        if( $data['height'] ) update_post_meta( $post_id, '_cgc_canvas_height', $data['height'] );

        if ( is_wp_error( $post_id ) ) {
            return new WP_Error( 'rest_cannot_save_template', esc_html__( 'Could not save the template.', 'gift-card-studio' ), array( 'status' => 500 ) );
        }

        $image_data = $data['url'];

        if(  ! $image_data ) {
            return new WP_Error( 'rest_missing_image', esc_html__( 'Missing url data.', 'gift-card-studio' ), array( 'status' => 400 ) );
        }


        //upload the image to the media library
        $filename = uniqid() . '.png';

        $upload_dir = wp_upload_dir();
        $image_data = str_replace('data:image/png;base64,', '', $image_data);
        $image_data = str_replace(' ', '+', $image_data);
        $decoded_image = base64_decode($image_data);
        $file = $upload_dir['path'] . '/' . basename($filename);
        file_put_contents($file, $decoded_image);

        $wp_filetype = wp_check_filetype(basename($filename), null);

        $attachment = array(
            'post_mime_type' => $wp_filetype['type'],
            'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)),
            'post_content' => '',
            'post_status' => 'inherit',
            'guid' => $upload_dir['url'] . '/' . basename($filename),
            'post_author' => $user_id
        );

        $attach_id = wp_insert_attachment($attachment, $file, $post_id);

        //cgc-design-image meta
        update_post_meta( $attach_id, 'cgc-design-image', true );

        //make the featured image
        set_post_thumbnail($post_id, $attach_id);

        if( ! empty( $data['form'] ) ){
            // Stash before $data gets reassigned below - add_to_cart() needs
            // the canvas JSON itself (not just the flat field values) to
            // detect {coupon_code}/{expire_date} tokens.
            $design_json_for_cart = $data['json'];
            $design_width_for_cart = $data['width'] ?? 0;
            $design_height_for_cart = $data['height'] ?? 0;

            $data = $data['form']['data'];
            $data['designID'] = $post_id;
            $data['attachID'] = $attach_id;
            return $this->add_to_cart( $data, $design_json_for_cart, $design_width_for_cart, $design_height_for_cart );
        }

        return rest_ensure_response( array( 'success' => true, 'card_id' => $post_id, 'attach_id' => $attach_id ) );
    }

}

new CGC_Rest_API();
?>