<?php

namespace AdvancedBlockControls;

// Exit if the file is accessed directly
if ( !defined('ABSPATH') ) {
    exit; 
}

class RestApiController

{
   
    private $RegistrationManager; // Instance of the Utils class for accessing utility methods

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

        $this->RegistrationManager = new RegistrationManager();
    }

     // function to sanitize json data
     public function jsonSanitize($data) {
        if (is_string($data)) {
            $data = json_decode($data, true);
        }

        if (is_array($data)) {
            foreach ($data as $key => $value) {
                if (is_array($value)) {
                    $data[$key] = $this->jsonSanitize($value);
                } else {
                    $data[$key] = sanitize_text_field($value);
                }
            }
        } else {
            $data = sanitize_text_field($data);
        }

        return wp_json_encode($data);
    }
    
    // Method to register the REST API route
    public function register_routes()
    {

        register_rest_route('advanced-block-controls/v1', '/settings', [
            'methods' => 'GET',
            'callback' => [$this, 'get_all_settings'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
            'show_in_index' => false,
        ]);

        // New route for saving an option
        register_rest_route('advanced-block-controls/v1', '/save-option', array(
            'methods' => 'POST',
            'callback' => [$this, 'handle_save_option'],
            'permission_callback' => [$this, 'save_option_permissions_check'],
            'show_in_index' => false,
        ));

        // Update a single block and its controls
        register_rest_route('advanced-block-controls/v1', '/save-block', [
            'methods' => 'POST',
            'callback' => [$this, 'handle_update_block_controls'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
            'show_in_index' => false,
        ]);

        // Route to reset control settings
        register_rest_route('advanced-block-controls/v1', '/reset-control-settings', [
            'methods' => 'POST',
            'callback' => [$this, 'handle_reset_control_settings'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
            'show_in_index' => false,
        ]);

        // Route to export settings
        register_rest_route('advanced-block-controls/v1', '/export-control-settings', [
            'methods' => 'GET',
            'callback' => [$this, 'handle_export_control_settings'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
            'show_in_index' => false,
        ]);

        // Route to import settings
        register_rest_route('advanced-block-controls/v1', '/import-control-settings', [
            'methods' => 'POST',
            'callback' => [$this, 'handle_import_control_settings'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
            'show_in_index' => false,
        ]);
    }

    public function handle_update_block_controls($request)
    {
        global $wpdb;
        $params = $request->get_json_params();
        $block_name = sanitize_text_field($params['block_name']);
        $block_target = $this->jsonSanitize($params['target']);
        $controls = $params['controls'];

        // Begin transaction
        $wpdb->query('START TRANSACTION');

        $currentTime = gmdate("Y-m-d H:i:s");
    
        try {
            // Check if block exists
            $existing_block = $wpdb->get_row($wpdb->prepare("SELECT id FROM {$wpdb->prefix}" . RegistrationManager::BLOCKS_TABLE_NAME . " WHERE block_name = %s", $block_name));
            $block_id = $existing_block ? $existing_block->id : null;
    
            $defaultControlStates = [];
            $changedDefaultStates = [];

            if ($existing_block && 'core_default' === $block_name) {
                $defaultControlStates = $wpdb->get_results(
                    $wpdb->prepare(
                        "SELECT id, state FROM {$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME . " WHERE blockId = %d",
                        $block_id
                    ),
                    ARRAY_A
                );

                if (!empty($defaultControlStates)) {
                    $defaultControlStates = array_column($defaultControlStates, 'state', 'id');
                }
            }

            if ($existing_block) {
                // Update the existing block
                $wpdb->update("{$wpdb->prefix}" . RegistrationManager::BLOCKS_TABLE_NAME, ['target' => $block_target, 'date_edited' => $currentTime,  'is_default_settings' => false], ['id' => $block_id]);

                // Updating existing controls and inserting new ones
                foreach ($controls as $controlSlug => $controlData) {
                    $controlId = sanitize_text_field($controlData['id']);
                 
                    $controlState = sanitize_text_field($controlData['state']);

                    // We only need this here to check if the control is being trashed
                    if ($controlState === 'trash') {
                        // Delete the control
                        $wpdb->delete("{$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME, ['id' => $controlId]);
                    } else {
                        $controlArray = [
                            'title' => sanitize_text_field($controlData['title']),
                            'type' => sanitize_text_field($controlData['type']),
                            'state' => sanitize_text_field($controlData['state']),
                            'target' => $this->jsonSanitize($controlData['target']),
                            'blockId' => $block_id,
                            'order_num' => sanitize_text_field($controlData['order_num']),
                            'date_edited' => $currentTime
                        ];
                    
                        if ($controlId) {
                            if ('core_default' === $block_name && isset($defaultControlStates[$controlId]) && $defaultControlStates[$controlId] !== $controlState) {
                                $changedDefaultStates[$controlId] = $controlState;
                            }

                            // Update existing control
                            $wpdb->update("{$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME , $controlArray, ['id' => $controlId]);
                        } else {
                            // Insert new control
                            $wpdb->insert("{$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME , $controlArray);
                        }
                    }
                } 
            } else {
                // Insert new block
                $wpdb->insert("{$wpdb->prefix}" . RegistrationManager::BLOCKS_TABLE_NAME, ['block_name' => $block_name, 'target' => $block_target, 'date_edited' => $currentTime, 'is_default_settings' => false]);
                $block_id = $wpdb->insert_id;

                // Inserting the controls
                foreach ($controls as $controlSlug => $controlData) {
                    $controlId = sanitize_text_field($controlData['id']);
                    
                    $controlState = sanitize_text_field($controlData['state']);

                    // We only need this here to check if the control is being trashed
                    if ($controlState === 'trash') {
                        // Delete the control
                        $wpdb->delete("{$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME, ['id' => $controlId]);
                    } else {

                        $default_clone = sanitize_text_field($controlData['default_clone']);
                    
                        $default_id = null;
                        if($default_clone) {
                            $default_id = $controlId;
                        }
                        $controlArray = [
                            'title' => sanitize_text_field($controlData['title']),
                            'default_clone' => $default_clone,
                            'default_id' => $default_id,
                            'type' => sanitize_text_field($controlData['type']),
                            'state' => sanitize_text_field($controlData['state']),  
                            'target' => $this->jsonSanitize($controlData['target']),
                            'blockId' => $block_id,
                            'order_num' => sanitize_text_field($controlData['order_num']),
                            "date_edited" => $currentTime
                        ];
                    
                        // Insert all the controls
                        $wpdb->insert("{$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME, $controlArray);
                    } 
                }   
            }
    
            if ('core_default' === $block_name && !empty($changedDefaultStates)) {
                $controlsTable = "{$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME;
                $blocksTable = "{$wpdb->prefix}" . RegistrationManager::BLOCKS_TABLE_NAME;

                foreach ($changedDefaultStates as $defaultControlId => $newState) {
                    $wpdb->query(
                        $wpdb->prepare(
                            "UPDATE {$controlsTable} c
                             INNER JOIN {$blocksTable} b ON b.id = c.blockId
                             SET c.state = %s,
                                 c.date_edited = %s
                             WHERE c.default_id = %d
                               AND b.is_default_settings = %s
                               AND b.block_name LIKE %s
                               AND b.id <> %d",
                            $newState,
                            $currentTime,
                            $defaultControlId,
                            '1',
                            'core/%',
                            $block_id
                        )
                    );
                }
            }

            // Commit transaction
            $wpdb->query('COMMIT');
    
            // Fetch updated controls
            $updatedControls = $this->get_controls_for_block($block_id);
    
            // Prepare response data
            $responseData = [
                'block_name' => $block_name,
                'id' => $block_id,
                'target' => $block_target,
                'date_edited' => $currentTime,
                'controls' => $updatedControls 
            ];
    
            return new \WP_REST_Response([
                'message' => 'Block and controls updated successfully',
                'data' => $responseData
            ], 200);
        } catch (Exception $e) {
            // Rollback transaction in case of error
            $wpdb->query('ROLLBACK');
            return new \WP_Error('db_error', $e->getMessage(), ['status' => 500]);
        }
    }
    
    private function get_controls_for_block($blockId)
    {
        global $wpdb;
    
        $sql = $wpdb->prepare(
            "SELECT id, title, type, state, target, order_num, date_edited, default_clone, default_id
            FROM {$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME . " WHERE blockId = %d AND state != %s ORDER BY order_num",
            $blockId,
            'trash'
        );
    
        $results = $wpdb->get_results($sql, ARRAY_A);
        $controls = [];
    
        foreach ($results as $row) {
            
            $controlSlug = $row['type'] . '_' . $row['id'];
            
            $controls[$controlSlug] = [
                'id' => $row['id'],
                'default_clone' => $row['default_clone'],
                'default_id' => $row['default_id'],
                'title' => $row['title'],
                'type' => $row['type'],
                'state' => $row['state'],
                'target' => $this->jsonSanitize($row['target']),
                'order_num' => $row['order_num'],
                'date_edited' => $row['date_edited']
            ];
        }
    
        return $controls;
    }
    

    // Callback method for the REST API route
    public function get_all_settings()
    {
        $options = $this->get_options();
        $block_controls = $this->get_block_controls();
        $deny_list = $this->get_deny_list();
        $response = [
            'options' => $options,
            'deny_list' => $deny_list,
            'controls' => $block_controls,
        ];

        return rest_ensure_response($response);
    }

    // Method to retrieve general settings from the options table
    private function get_options()
    {
        // Retrieve and decode the option
        $settings_option = get_option('abcon_settings');
        $settings = json_decode($settings_option, true);

        return  $settings;
    }

    // Metho to retieve denied blocks lisr 
    private function get_deny_list()
    {
        // Retrieve and decode the option
        $deny_list_option = get_option('abcon_deny_list');
        $deny_list  = json_decode($deny_list_option, true);

        return $deny_list;
    }

    public function get_block_controls()
    {
        if($this->RegistrationManager->blocks_table_exists() && $this->RegistrationManager->controls_table_exists()) {
        
            global $wpdb;

            // SQL to retrieve blocks and their related controls, excluding controls with state 'trash'
            $sql = "SELECT b.id as block_id, b.block_name, b.target as block_target, b.is_default_settings,  
                        b.date_edited as block_edit_date, c.id as control_id, c.title, c.type, c.state, c.target as control_target, 
                        c.config, c.order_num, c.default_clone, c.default_id, c.date_edited as control_edit_date 
                        FROM {$wpdb->prefix}" . RegistrationManager::BLOCKS_TABLE_NAME . " b
                    LEFT JOIN {$wpdb->prefix}" . RegistrationManager::CONTROLS_TABLE_NAME . " c ON b.id = c.blockId AND c.state != 'trash'
                    ORDER BY b.id, c.order_num, c.id";

            $results = $wpdb->get_results($sql, ARRAY_A);

            $blocks = array();
            foreach ($results as $row) {
                // Initialize block if it hasn't been added to $blocks array
                if (!isset($blocks[$row['block_name']])) {
                    $blocks[$row['block_name']] = array(
                        'id' => $row['block_id'],
                        'block_name' => $row['block_name'],
                        'target' => $this->jsonSanitize($row['block_target']),
                        'date_edited' => $row['block_edit_date'],
                        'is_default_settings' => $row['is_default_settings'],
                        'controls' => array()
                    );
                }

                // Add control to this block using type_controlId as the key
                if ($row['control_id']) {
                
                    $controlSlug = $row['type'] . '_' . $row['control_id'];
                
                    $blocks[$row['block_name']]['controls'][$controlSlug] = array(
                        'id' => $row['control_id'],
                        'default_clone' => $row['default_clone'],
                        'default_id' => $row['default_id'],
                        'title' => $row['title'],
                        'type' => $row['type'],
                        'state' => $row['state'],
                        'target' => $this->jsonSanitize($row['control_target']),
                        'order_num' => $row['order_num'],
                        'date_edited' => $row['block_edit_date'],
                        'config' => json_decode($row['config'], true)
                    );
                }
            }

            return $blocks;
        }

        return array();
    }


    // Method to handle saving an option
    public function handle_save_option($request)
    {
        // Decode the JSON body from the request
        $params = json_decode($request->get_body(), true);

        // Extract the option name and value
        $option_name = array_key_first($params);
        $option_value = $params[$option_name];

        if (empty($option_name)) {
            return new \WP_Error('missing_option_name', 'Option name is required', array('status' => 400));
        }

        // return new \WP_REST_Response([
        //     'message' => 'Option test',
        //     'data' =>  [
        //         'option_name' => $option_name,
        //         'option_value' => $option_value
        //     ]
        // ], 200);

        $result = update_option($option_name, $option_value);

        // return new \WP_REST_Response([
        //     'message' => 'Option test kljlk',
        //     "name" => $option_name,
        //     'data' => $option_value,
        //     "result" =>  $result
        // ], 200);


        $response = get_option($option_name);

        if ($result) {
            return new \WP_REST_Response([
                'message' => 'Option Have been saved successfully',
                'data' =>  [
                    'option_name' => $option_name,
                    'option_value' => $response
                ]
            ], 200);
        } else {
            return new \WP_Error('db_error', 'Failed to save the option', array('status' => 500));
        }

    }

    // Method for permission check
    public function save_option_permissions_check($request)
    {
        return current_user_can('manage_options');
    }

    // Handle reset control settings
    public function handle_reset_control_settings($request)
    {
        try {
            $this->RegistrationManager->reset_control_settings();

            return new \WP_REST_Response([
                'message' => 'Controls settings have been reset successfully.',
            ], 200);
        } catch (\Exception $e) {
            return new \WP_Error('reset_failed', 'Failed to reset controls settings.', ['status' => 500]);
        }
    }

    // Handle export control settings
    public function handle_export_control_settings($request)
    {
        try {
            $exportData = $this->RegistrationManager->export_control_settings();

            return new \WP_REST_Response($exportData, 200);
        } catch (\Exception $e) {
            return new \WP_Error('export_failed', 'Failed to export controls settings.', ['status' => 500]);
        }
    }

    // Handle import control settings
    public function handle_import_control_settings($request)
    {
        try {
            $importData = json_decode($request->get_body(), true);

            if (empty($importData)) {
                return new \WP_Error('invalid_json', 'Invalid or empty JSON data.', ['status' => 400]);
            }

            $this->RegistrationManager->import_control_settings($importData);

            return new \WP_REST_Response([
                'message' => 'Settings imported successfully.',
            ], 200);
        } catch (\Exception $e) {
            return new \WP_Error('import_failed', $e->getMessage(), ['status' => 400]);
        }
    }
}
