<?php

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Class Irep_Meta_Project
 *
 * Manages the creation, retrieval, and updating of project metadata in the database.
 * This class provides methods to get project metadata and to either create new metadata or update existing metadata.
 */
class Irep_Meta_Project
{
    // Database connection object
    protected $wpdb;

    // Table name for storing project metadata
    protected $table_name;

    /**
     * Constructor to initialize the database connection and table name.
     * This method is called automatically when an instance of the class is created.
     */
    public function __construct()
    {
        global $wpdb;
        $this->wpdb = $wpdb;
        $this->table_name =  'irep_project_meta';  // Table for project metadata
    }

    /**
     * Retrieves project metadata from the database based on the provided project ID.
     *
     * @param array $data The request data containing the project ID and nonce for security validation.
     * 
     * @return array A two-element array:
     *               - bool: Success status of the operation.
     *               - array: The metadata results or an error message.
     */
    public function get_meta(array $data)
    {
        $data = [
            'nonce'        => isset($data['nonce']) ? sanitize_text_field($data['nonce']) : '',
            'action'       => isset($data['action']) ? sanitize_key($data['action']) : '',
            'project_id'   => isset($data['project_id']) ? absint($data['project_id']) : 0,
        ];

        // Verify the nonce for security and check if project ID is valid
        irep_check_nonce($data['nonce'], 'irep_nonce');
        irep_has_project_id($data);

        $query = Irep_DB::table($this->table_name);

        $query->where('project_id', '=', $data['project_id']);

        $results = $query->get();

        // Only a real DB failure is an error. A project with no meta rows is
        // valid and must still fall through so site-wide custom types are merged.
        if ($results === false || $results === null) {
            return [false,  'No meta found.'];
        }

        if (!is_array($results)) {
            $results = [];
        }

        // Parse JSON meta_value for keys that store JSON (array/object) for the response
        $json_meta_keys = array(
            'custom_types',
            'price_filter_options',
            'area_filter_options',
            'rooms_filter_options',
            'filter_options',
        );
        foreach ($results as $row) {
            if (!isset($row->meta_key) || !isset($row->meta_value) || !is_string($row->meta_value)) {
                continue;
            }
            if (!in_array($row->meta_key, $json_meta_keys, true)) {
                continue;
            }
            $value = stripslashes($row->meta_value);
            $decoded = json_decode($value);
            if (json_last_error() === JSON_ERROR_NONE) {
                $row->meta_value = $decoded;
            }
        }

        $results = $this->merge_custom_types_from_options($results, $data['project_id']);

        return [true, $results];
    }

    /**
     * Merges 'custom_types' from the options table (site-wide) into the meta results.
     *
     * @param array $results    Meta rows from the database.
     * @param int   $project_id Current project ID for the synthetic row if needed.
     * @return array The same array with custom_types key present and value from options.
     */
    private function merge_custom_types_from_options($results, $project_id)
    {
        $custom_types_value = get_option(IREP_OPTION_CUSTOM_STATUS_TYPES, '[]');
        if (is_string($custom_types_value)) {
            $custom_types_value = stripslashes($custom_types_value);
            $decoded = json_decode($custom_types_value);
            $custom_types_value = (json_last_error() === JSON_ERROR_NONE && (is_array($decoded) || is_object($decoded)))
                ? (is_array($decoded) ? $decoded : (array) $decoded)
                : [];
        }
        $custom_types_value = is_array($custom_types_value) ? $custom_types_value : [];
        $found = false;
        foreach ($results as $row) {
            if (isset($row->meta_key) && $row->meta_key === 'custom_types') {
                $row->meta_value = $custom_types_value;
                $found = true;
                break;
            }
        }
        if (!$found) {
            $results[] = (object) [
                'id'         => 0,
                'project_id' => $project_id,
                'meta_key'   => 'custom_types',
                'meta_value' => $custom_types_value,
                'created_at' => null,
                'updated_at' => null,
            ];
        }
        return $results;
    }

    /**
     * Creates or updates project metadata in the database.
     *
     * @param array $data The request data containing project ID, nonce, and metadata to be created or updated.
     * 
     * @return void
     */
    public function create_or_update_meta($data)
    {
        $data = [
            'nonce'        => isset($data['nonce']) ? sanitize_text_field($data['nonce']) : '',
            'action'       => isset($data['action']) ? sanitize_key($data['action']) : '',
            'project_id' => isset($data['project_id']) ? absint($data['project_id']) : 0,
            'meta_data' => $data['meta_data']
        ];



        if (!ire_fs()->can_use_premium_code()) {
            // Free plan
            $allowed_keys = ['tooltip', 'price_rounded', 'area_unit', 'flat_preview', 'flat_preview_one_style', 'flat_preview_default_plan', 'is_360_flow', 'paths_hover_fill', 'loop_360', 'speed_360', 'reverse_360', 'sidebar_open_360', 'request_price_type', 'request_price_phone', 'request_price_url', 'request_price_message', 'primary_mobile_image', 'mobile_breakpoint'];

            $data['meta_data'] = array_filter($data['meta_data'], function ($item) use ($allowed_keys) {

                if ($item['key'] === 'currency') {
                    $available_currencies = ['usd'];
                    return in_array($item['value'], $available_currencies);
                };

                return in_array($item['key'], $allowed_keys);
            });
        } else if (!ire_fs()->is_plan_or_trial('gold', true)) {
            // Premimum plan
            $disallowed_keys = ['request_callback', 'redirect_to_callback_url', 'shareable_link', 'receive_forms_on_email', 'custom_types'];
            $data['meta_data'] = array_filter($data['meta_data'], fn($item) => !in_array($item['key'], $disallowed_keys));
        }


        // Verify the nonce for security and check if project ID is valid
        irep_check_nonce($data['nonce'], 'irep_nonce');
        irep_has_project_id($data);

        // Ensure 'meta_data' is provided and is an array
        if (!isset($data['meta_data']) || !is_array($data['meta_data'])) {
            irep_send_json_response(false, 'Required fields are missing.');
            return;
        }

        // Iterate through each metadata item
        foreach ($data['meta_data'] as $meta) {
            // Validate each meta key-value pair
            if (empty($meta['key']) || !isset($meta['value'])) {
                irep_send_json_response(false, 'Meta key or value is missing.');
                return;
            }

            // Sanitize and prepare the meta data
            $project_id = $data['project_id'];
            $meta_key = sanitize_text_field($meta['key']);
            $meta_value = sanitize_textarea_field($meta['value']);


            $query = Irep_DB::table($this->table_name);


            $existing_meta = $query->where('project_id', '=', $project_id)->where('meta_key', '=', $meta_key)->get();

            $update_query = Irep_DB::table($this->table_name);


            if ($existing_meta) {
                $params =  ['meta_value' => $meta_value];


                $update_result = $update_query->where('id', '=',  $existing_meta[0]->id)->update($params);


                // If the update fails, send an error response
                if ($update_result->last_error) {
                    irep_send_json_response(false, 'Database error during update');
                    return;
                }
            } else {
                $data =  [
                    'project_id' => $project_id,
                    'meta_key' => $meta_key,
                    'meta_value' => $meta_value,
                ];

                $insert_result = Irep_DB::table($this->table_name)->create($data);

                // If the insert fails, send an error response
                if (!$insert_result) {
                    irep_send_json_response(false, 'Database error during insert');
                    return;
                }
            }
        }

        // Send success response once the metadata has been added or updated
        irep_send_json_response(true, 'Meta added or updated successfully');
    }
}

// Initialize the class to create an instance of Irep_Meta_Project
$irep_meta = new Irep_Meta_Project();

/**
 * Action function to retrieve project metadata via AJAX.
 * This function is hooked to the 'wp_ajax_irep_get_meta' action.
 */
function irep_get_meta()
{
    global $irep_meta;

    // Call the get_meta method of the Irep_Meta_Project class
    $results = $irep_meta->get_meta($_POST);

    // Send a JSON response based on the results
    if (!$results[0]) {
        irep_send_json_response(false, $results[1]);
    } else {
        irep_send_json_response(true, $results[1]);
    }
}

/**
 * Action function to create or update project metadata via AJAX.
 * This function is hooked to the 'wp_ajax_irep_create_or_update_meta' action.
 */
function irep_create_or_update_meta()
{
    global $irep_meta;

    // Call the create_or_update_meta method of the Irep_Meta_Project class
    $irep_meta->create_or_update_meta($_POST);
}

// Add AJAX action hooks for retrieving and creating/updating project metadata
add_action('wp_ajax_irep_get_meta', 'irep_get_meta');
add_action('wp_ajax_irep_create_or_update_meta', 'irep_create_or_update_meta');

/**
 * Site-wide custom status types (shared across all projects).
 * Stored via WordPress options; no project_id.
 */
define('IREP_OPTION_CUSTOM_STATUS_TYPES', 'irep_custom_status_types');

function irep_get_custom_status_types()
{
    irep_check_nonce(isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '', 'irep_nonce');

    $raw = get_option(IREP_OPTION_CUSTOM_STATUS_TYPES, '[]');
    if (!is_string($raw)) {
        irep_send_json_response(true, is_array($raw) ? $raw : []);
        return;
    }
    $normalized = stripslashes($raw);
    $decoded = json_decode($normalized);
    if (json_last_error() === JSON_ERROR_NONE) {
        $list = is_array($decoded) ? $decoded : (is_object($decoded) ? (array) $decoded : []);
        irep_send_json_response(true, $list);
        return;
    }
    irep_send_json_response(true, []);
}

function irep_update_custom_status_types()
{
    irep_check_nonce(isset($_POST['nonce']) ? sanitize_text_field($_POST['nonce']) : '', 'irep_nonce');

    if (!ire_fs()->is_plan_or_trial('gold', true)) {
        irep_send_json_response(false, 'Gold plan required.');
        return;
    }

    $value = isset($_POST['value']) ? wp_unslash($_POST['value']) : '';
    if ($value === '') {
        update_option(IREP_OPTION_CUSTOM_STATUS_TYPES, '[]');
        irep_send_json_response(true, []);
        return;
    }

    $decoded = json_decode($value);
    if (!is_array($decoded)) {
        irep_send_json_response(false, 'Invalid data.');
        return;
    }

    update_option(IREP_OPTION_CUSTOM_STATUS_TYPES, $value);
    irep_send_json_response(true, $decoded);
}

add_action('wp_ajax_irep_get_custom_status_types', 'irep_get_custom_status_types');
add_action('wp_ajax_irep_update_custom_status_types', 'irep_update_custom_status_types');
