<?php 
// ******** BLOCK CATEGORIES **********
function scroll_sequence_v2_block_categories( $categories, $post ) {
    $scroll_sequence_category = array(
        'slug'  => 'scroll-sequence',
        'title' => 'Scrollsequence',
        'icon'  => null, // Optional: Dashicon slug
    );

    // Find index of 'media' category
    $insert_after = array_search( 'media', array_column( $categories, 'slug' ) );

    if ( $insert_after !== false ) {
        // Insert after 'media'
        $before = array_slice( $categories, 0, $insert_after + 1 );
        $after = array_slice( $categories, $insert_after + 1 );
        $categories = array_merge( $before, array( $scroll_sequence_category ), $after );
    } else {
        // Fallback: add to the end
        $categories[] = $scroll_sequence_category;
    }

    return $categories;
}
add_filter( 'block_categories_all', 'scroll_sequence_v2_block_categories', 10, 2 );

// ******** SHARED STYLES *************
function scroll_sequence_v2_view_style_noscript() {
    wp_register_style( 'scroll-sequence-v2-style-view', plugin_dir_url( __FILE__ ) . 'build/v2/blocks/style-view.css', [], SCROLLSEQUENCE_VERSION  );
}
add_action( 'enqueue_block_assets', 'scroll_sequence_v2_view_style_noscript' );

// noscript styles 
function scroll_sequence_v2_noscript_style($html, $handle, $href, $media) {
    $parent_style_handle = 'scroll-sequence-v2-style-view';
    $inline_css = '
        .ssq-noscript-relative {
            position:relative!important;
        }
        .ssq-noscript-h-100vh {
            height:100vh!important;
        }
        .ssq-not-hydrated{
            visibility:initial!important;
        }
    ';
    $noscript_css = "<noscript>\n<style>\n" . $inline_css . "\n</style>\n</noscript>\n";
    if ($handle === $parent_style_handle) {
        return $html . "\n" . $noscript_css; // Append after
    }
    return $html;
}
add_filter('style_loader_tag', 'scroll_sequence_v2_noscript_style', 10, 4);

// ******** BLOCK REGISTRATIONS *************

// canvas1d (not ready yet)
// function scroll_sequence_v2_scroll_sequence_canvas1d_register_block() {
//     register_block_type( __DIR__ . '/build/v2/blocks/canvas1d' );
// }
// add_action( 'init', 'scroll_sequence_v2_scroll_sequence_canvas1d_register_block' );

// canvas2d
function scroll_sequence_v2_scroll_sequence_canvas2d_register_block() {
    register_block_type( __DIR__ . '/build/v2/blocks/canvas2d' );
}
add_action( 'init', 'scroll_sequence_v2_scroll_sequence_canvas2d_register_block' );

// canvas3d
function scroll_sequence_v2_scroll_sequence_canvas3d_register_block() {
    register_block_type( __DIR__ . '/build/v2/blocks/canvas3d' );
}
add_action( 'init', 'scroll_sequence_v2_scroll_sequence_canvas3d_register_block' );

// container 
function scroll_sequence_v2_container_register_block() {
    register_block_type( __DIR__ . '/build/v2/blocks/container' );
}
add_action( 'init', 'scroll_sequence_v2_container_register_block' );

// scene
function scroll_sequence_v2_scene_register_block() {
    register_block_type( __DIR__ . '/build/v2/blocks/scene' );
}
add_action( 'init', 'scroll_sequence_v2_scene_register_block' );



// 2 Editor 
/*
Scenarios for enqueuing assets
    Editor scripts and styles
    Whenever you need to enqueue assets for the Editor itself (i.e. not the user-generated content), 
    you should use the enqueue_block_editor_assets hook coupled with the standard wp_enqueue_script and wp_enqueue_style functions.
see: https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/
*/
function scroll_sequence_v2_scroll_sequence_extend_block(){
    if ( freemius_scrollsequence()->can_use_premium_code__premium_only() ) { // instead of     is_plan_or_trial__premium_only('PRO'))
        $pro_asset_file = include( plugin_dir_path( __FILE__ ) . 'build/premium/blocks/extend-blocks.asset.php');
        wp_enqueue_script(
            'scroll-sequence-v2-scroll-sequence-premium',
            plugins_url( 'build/premium/blocks/extend-blocks.js', __FILE__ ),
            $pro_asset_file['dependencies'],
            $pro_asset_file['version'],
            true
        );
    }    
}
add_action('enqueue_block_editor_assets', 'scroll_sequence_v2_scroll_sequence_extend_block');

// EDITOR - IFRAME ONLY 

// 3 View  - Register two different scripts with the same handle depending on the lic
function scroll_sequence_v2_scroll_sequence_register_iframe_scripts(){
    if ( freemius_scrollsequence()->can_use_premium_code__premium_only() ) { // instead of     is_plan_or_trial__premium_only('PRO'))
        //echo '<h1>3VIEWFOP-premium</h1><h1>3VIEWFOP-premium</h1><h1>3VIEWFOP-premium</h1><h1>3VIEWFOP-premium</h1>';

        // GSAP 3.12.5
        wp_register_script(
            'gsap', // SSQ1 Handle 'gsap' but in their docs they recommend 'gsap-js'
            plugins_url( 'premium/includes/gsap-3.12.7/gsap.min.js', __FILE__ ),
            [ ],
            '3.12.7',
            true
        );
        // SCROLLTRIGGER 3.12.5
        wp_register_script(
            'scrolltrigger', // SSQ1 Handle 'scrolltrigger' but in their docs they recommend 'gsap-st'
            plugins_url( 'premium/includes/gsap-3.12.7/scrolltrigger.min.js', __FILE__ ),
            [ 'gsap' ],
            '3.12.7',
            true
        );



        $asset_file = include( plugin_dir_path( __FILE__ ) . 'build/premium/blocks/view-premium.asset.php'); // automatically load dependencies and version

        // premium library 
        wp_register_script(
            'scroll-sequence-v2-library-premium',
            plugins_url( 'premium/includes/ssqlib/scroll-sequence-lib-premium.min.js', __FILE__ ),
            [ 'gsap', 'scrolltrigger' ], // here I could add 'gsap' 
            $asset_file['version']."-".SCROLLSEQUENCE_VERSION,
            true
        );

        // view editor script
        wp_register_script(
            'scroll-sequence-v2-view-fop',
            plugins_url( 'build/premium/blocks/view-premium.js', __FILE__ ),
            [ 'scroll-sequence-v2-library-premium' ], // 'gsap', 'scrolltrigger'
            $asset_file['version']."-".SCROLLSEQUENCE_VERSION,
            true
        );
    } else { // !!!! I NEED TO TEST IF THE "ELSE" GETS STRIPPED CORRECTLY OR NOT
        //echo '<h1>3VIEWFOP-free</h1><h1>3VIEWFOP-free</h1><h1>3VIEWFOP-free</h1><h1>3VIEWFOP-free</h1>';


        // GSAP 3.12.5 loaded from a CDN 
        wp_register_script(
            'gsap', // SSQ1 Handle 'gsap' but in their docs they recommend 'gsap-js'
            'https://cdn.jsdelivr.net/npm/gsap@3.12.7/dist/gsap.min.js',
            [ ],
            '3.12.7',
            true
        );

        // SCROLLTRIGGER 3.12.5 loaded from a CDN
        wp_register_script(
            'scrolltrigger', // SSQ1 Handle 'scrolltrigger' but in their docs they recommend 'gsap-st'
            'https://cdn.jsdelivr.net/npm/gsap@3.12.7/dist/ScrollTrigger.min.js',
            [ 'gsap' ],
            '3.12.7',
            true
        );


        $asset_file = include( plugin_dir_path( __FILE__ ) . 'build/v2/blocks/view.asset.php'); // automatically load dependencies and version

        // free library 
        wp_register_script(
            'scroll-sequence-v2-library-free',
            plugins_url( 'includes/ssqlib/scroll-sequence-lib-free.min.js', __FILE__ ),
            [ 'gsap', 'scrolltrigger' ],
            $asset_file['version']."-".SCROLLSEQUENCE_VERSION,
            true
        );     

        // Block editor script
        wp_register_script(
            'scroll-sequence-v2-view-fop',
            plugins_url( 'build/v2/blocks/view.js', __FILE__ ),
            [ 'scroll-sequence-v2-library-free' ],
            $asset_file['version']."-".SCROLLSEQUENCE_VERSION,
            true
        );

    }    

    $data = array(
        //'foo' => 'bar',
        'wpApiSettings' => [
           'root' => esc_url_raw( rest_url() ),
           'nonce' => wp_create_nonce( 'wp_rest' ),
           //'versionString' => 'todo' // this property is present on the standard wpApiRoot, i guess I am going to need it at some point
        ], 

    );
    wp_localize_script('scroll-sequence-v2-view-fop', 'scrollSequenceLocalize', $data);


    // SPLINE
    // wp_register_script_module(
    //     'spline-runtime', 
    //     plugins_url( 'includes/spline/runtime-1.9.12.js', __FILE__ ), // external url: https://unpkg.com/@splinetool/runtime@1.9.12/build/runtime.js
    //     [  ], // deps
    //     '1.9.12',
    //     true
    // );

}
add_action('enqueue_block_assets', 'scroll_sequence_v2_scroll_sequence_register_iframe_scripts'); // Register and enqueue stylesheet/scripts for the iframe editor content only.

/**
 * 
 * THIS IS A HACK THAT ONLY ENQUEUES THE LIBRARY SCRIPT IN IFRAME AND NOT IN THE EDITOR!!!!
 * 
 * !!! Not sure how it works in older versions of WP and in API v2 (without iframe)
 * 
 * !!! TODO: Really I need to make sure, the library works fine even if runs twice (once in editor, then in iframe)
 *  see: https://github.com/WordPress/gutenberg/issues/53590
 */
// This tries to remove the script from being enqueued in the editor (and leave it only in iframe)
add_action('admin_enqueue_scripts', function () {
    wp_deregister_script('scroll-sequence-v2-view-fop');
});












/**
 * 
 *  HOCS
 * 
 * 
 */
function scroll_sequence_v2_hocs(){
    $hoc_content_animation_asset_file = include( plugin_dir_path( __FILE__ ) . 'build/v2/hocs/index.asset.php');
    wp_enqueue_script(
        'scroll-sequence-v2-hocs',
        plugins_url( 'build/v2/hocs/index.js', __FILE__ ),
        $hoc_content_animation_asset_file['dependencies'],
        $hoc_content_animation_asset_file['version'],
        true
    );
}
add_action('enqueue_block_editor_assets', 'scroll_sequence_v2_hocs');



/**
 * 
 * REST API STUFF 
 * 
 */



/**
 * Canvas 2d Custom REST API endpoint
 *  - this endpoint accepts post request with ids that is an array of ids and a width which is the desired width of the image in pixels. 
 *  - it returns an array of the shape [{id:number, url:string}, ...]. 
 */
add_action('rest_api_init', function () {
    register_rest_route('scroll-sequence/v2', '/canvas2d/image-urls', [
        'methods'  => 'POST',
        'callback' => 'scroll_sequence_v2_canvas_2d_image_urls',
        'args'     => [
            'payload' => [
                'required' => true,
                'validate_callback' => function ($param) {
                    // Validate payload structure
                    // if (!is_array($param) || count($param) > 300) { // instead of "refuse to process" I could just limit the array size to 300
                    //     return false; // Limit array size to 300 entries
                    // }
                    foreach ($param as $item) {
                        if (!isset($item['id'], $item['width']) || 
                            !is_numeric($item['id']) || 
                            !is_numeric($item['width']) || 
                            $item['width'] <= 0) {
                            return false;
                        }
                    }
                    return true;
                },
            ],
        ],
        'permission_callback' => '__return_true', // Allow access to all users
    ]);
});

function scroll_sequence_v2_canvas_2d_image_urls(WP_REST_Request $request) {
    $payload = $request->get_param('payload');
    $response = [];

    // Deduplicate by IDs to avoid redundant processing
    $unique_payload = [];
    foreach ($payload as $item) {
        $id = absint($item['id']);
        $width = absint($item['width']);
        $unique_payload["$id-$width"] = $item; // Unique key based on ID and width
    }
    //error_log($unique_payload); - write unique payload to error log for debugging. 


    // Generate a cache key
    $cache_key = 'scrollsequence_canvas2d__' . md5(json_encode($unique_payload)); 
    $cached_response = get_transient($cache_key); // !!!! TODO: Check that this works (unique id and transient caching)

    // Return cached response if available
    if ($cached_response) {
        return rest_ensure_response($cached_response); // this can be commented out to prevent stale response in dev. 
    }

    // Process each unique entry
    foreach ($unique_payload as $item) {
        $id = absint($item['id']);
        $width = absint($item['width']);

        $image_meta = wp_get_attachment_metadata($id);
        if (!$image_meta) {
            continue; // Skip if metadata not found
        }

        // Find the closest matching size
        $best_fit_url = null;
        $closest_width = PHP_INT_MAX;

        if (isset($image_meta['sizes']) && is_array($image_meta['sizes'])) {
            foreach ($image_meta['sizes'] as $size_name => $size_data) {
                $current_width = $size_data['width'];
                if (abs($width - $current_width) < abs($width - $closest_width)) {
                    $closest_width = $current_width;
                    $closest_height = $size_data['height']; // optional ?
                    $best_fit_url = wp_get_attachment_image_url($id, $size_name);
                }
            }
        }

        // Fallback to the full image if no match is found
        if (!$best_fit_url) {
            $best_fit_url = wp_get_attachment_url($id);
        }

        $response[] = [
            'id'  => $id,
            //'url' => $best_fit_url, // Does not really work
            'url' => wp_get_attachment_image_url($id, 'full'), // Use full size URL as a fallback
            'width' => $width,
            'closest_width' => $closest_width, // optional ? 
            'closest_height' => $closest_height, // optional ? 
            'file_name' => basename(get_attached_file($id)), // file name (for sorting by name)
        ];
    }

    // Cache the response for 60 minutes
    set_transient($cache_key, $response, 60 * MINUTE_IN_SECONDS);

    return rest_ensure_response($response);
}





/**
 * Modify the rendered output of all blocks with scAnimationType attribute.
 *
 * @param string $block_content The normal block HTML that would be sent to the screen.
 * @param array  $block An array of data about the block, and the way the user configured it.
 */

function scroll_sequence_v1_scroll_sequence_animation_data_attributes_render( $block_content, $block ) {
    // content animation
	if ( isset( $block['attrs']['ssqAnimateOnLoad']) ) {
        $tags = new WP_HTML_Tag_Processor( $block_content );
        if ( $tags->next_tag() ) {
            $tags->set_attribute( 'data-ssq-animate-on-load', json_encode($block['attrs']['ssqAnimateOnLoad']) );
        }       
        $block_content = $tags->get_updated_html();
	}
	if ( isset( $block['attrs']['ssqAnimateOnClick']) ) {
        $tags = new WP_HTML_Tag_Processor( $block_content );
        if ( $tags->next_tag() ) {
            $tags->set_attribute( 'data-ssq-animate-on-click', json_encode($block['attrs']['ssqAnimateOnClick']) );
        }       
        $block_content = $tags->get_updated_html();
	}
	if ( isset( $block['attrs']['ssqAnimateOnHover']) ) {
        $tags = new WP_HTML_Tag_Processor( $block_content );
        if ( $tags->next_tag() ) {
            $tags->set_attribute( 'data-ssq-animate-on-hover', json_encode($block['attrs']['ssqAnimateOnHover']) );
        }       
        $block_content = $tags->get_updated_html();
	}    
	if ( isset( $block['attrs']['ssqAnimateOnScroll']) ) {
        $tags = new WP_HTML_Tag_Processor( $block_content );
        if ( $tags->next_tag() ) {
            $tags->set_attribute( 'data-ssq-animate-on-scroll', json_encode($block['attrs']['ssqAnimateOnScroll']) );
        }       
        $block_content = $tags->get_updated_html();
	}     
    // content pointer events
	if ( isset( $block['attrs']['ssqPointerEvents']) ) {
        $tags = new WP_HTML_Tag_Processor( $block_content );
        if ( $tags->next_tag() ) {
            // here i want to set the style attribute instead of data-ssq-pointer-events
            $pointer_events = $block['attrs']['ssqPointerEvents'];

            // This adds class name "ssq-pointer-events-none" to the tag // DOES NOT WORK, USING BELOW CODE INSTEAD.
            // if ( $pointer_events === 'none' ) {
            //     $tags->add_class( 'ssq-pointer-events-none' );
            // }

            // THIS CHANGES STYLE ATTRIBUTE
            if ( $pointer_events ) {
                $existing_style = $tags->get_attribute( 'style' );

                // Remove any existing pointer-events declarations
                if ( $existing_style ) {
                    $existing_style = preg_replace( '/\s*pointer-events\s*:\s*[^;]+;?/i', '', $existing_style );
                    $existing_style = trim( $existing_style );
                    if ( $existing_style !== '' && substr( $existing_style, -1 ) !== ';' ) {
                        $existing_style .= ';';
                    }
                } else {
                    $existing_style = '';
                }

                // Add the new pointer-events declaration
                $existing_style .= " pointer-events: {$pointer_events};";

                $tags->set_attribute( 'style', $existing_style );
            }
        }       
        $block_content = $tags->get_updated_html();
	}  


    // scene animation and alignment
	if ( isset( $block['attrs']['ssqSceneBegin']) ) {
        $tags = new WP_HTML_Tag_Processor( $block_content );
        if ( $tags->next_tag() ) {
            $tags->set_attribute( 'data-ssq-scene-begin', json_encode($block['attrs']['ssqSceneBegin']) );
        }       
        $block_content = $tags->get_updated_html();
	}         
	if ( isset( $block['attrs']['ssqSceneEnd']) ) {
        $tags = new WP_HTML_Tag_Processor( $block_content );
        if ( $tags->next_tag() ) {
            $tags->set_attribute( 'data-ssq-scene-end', json_encode($block['attrs']['ssqSceneEnd']) );
        }       
        $block_content = $tags->get_updated_html();
	}         
	if ( isset( $block['attrs']['ssqSceneAlign']) ) {
        $tags = new WP_HTML_Tag_Processor( $block_content );
        if ( $tags->next_tag() ) {
            $tags->set_attribute( 'data-ssq-scene-align', json_encode($block['attrs']['ssqSceneAlign']) ); // is this required?, we should do just className really ..
        }       
        $block_content = $tags->get_updated_html();
	}                 
	// For any other block, just return normal block output.
	return $block_content;

}
add_filter( 'render_block', 'scroll_sequence_v1_scroll_sequence_animation_data_attributes_render', 10, 2 );
