<?php

class RTSetOptions
{
    /**
     * Expected fields from Rentopian.
     */
    public $id
        ,$title
        ,$details
        ,$once_per_order;


    /**
     * Create a new instance.
     *
     * @param int $id
     * @param string $title
     * @param longtext $option_values
     */
    public function __construct($id, $title = '', $once_per_order = 0, $details = '')
    {
        $this->id = intval($id);
        $this->title = $title;
        $this->once_per_order = $once_per_order;
        $this->details = $details;
    }


    /**
     * Create or update a set_options.
     *
     * @return object
     */
    public function save()
    {
        global $wpdb, $rental_tables;
        $rental_set_options = $wpdb->prefix . $rental_tables["set_options"];

        $option_id = $this->id;
        $exists = $wpdb->get_var( $wpdb->prepare( "SELECT `id`, `option_values` FROM $rental_set_options WHERE `id` = %d ", [$this->id] ) );
        if ($exists) {
            // update
            $where = ['id' => $option_id];
            $result = $wpdb->update( $rental_set_options, [ 
                'title' => $this->title
                ,'once_per_order' => $this->once_per_order
                ,'option_values' => json_encode($this->details["option_values"])
            ], $where );

            $this->update($option_id);

            if (false === $result) {
                return $result;
            } 

        } else {
            // insert
            $result = $wpdb->insert( $rental_set_options, [ 
                'id' => $option_id
                ,'title' => $this->title
                ,'once_per_order' => $this->once_per_order
                ,'option_values' => json_encode($this->details["option_values"])
            ]);

            $this->create($option_id);
            
            if (false === $result) {
                return $result;
            }
        }

        return $option_id;
    }

    public function update($updated_option_id)
    {
        global $wpdb, $rental_tables;
        $rental_set_options = $wpdb->prefix . $rental_tables["set_options"];
        $rental_set_option_relations = $wpdb->prefix . $rental_tables["set_option_relations"];
        $rental_set_relations = $wpdb->prefix . $rental_tables["set_relations"];

        // collect every division's rental set ids
        $set_ids = $wpdb->get_results("SELECT id, rental_id FROM {$rental_set_relations}", ARRAY_A);

        $sql = "
            SELECT 
                options.*,
                GROUP_CONCAT(DISTINCT relation_sets.wp_id) wp_set_ids
            FROM 
                {$rental_set_options} as options
            LEFT JOIN {$rental_set_option_relations} as relation_sets ON relation_sets.set_option_id = options.id
            WHERE
                options.id <> %d
            GROUP BY
                options.id
        ";
        $set_options = $wpdb->get_results($wpdb->prepare($sql, $updated_option_id), ARRAY_A);

        $attached_items_grouped = [];
        // adding updated option
        $attached_items_grouped[$updated_option_id] = [
            'sets' => $this->details['sets_attached']
        ];
        // adding all other options
        foreach($set_options as $set_option) {
            $attached_items_grouped[$set_option['id']] = [
                'sets' => explode(',',$set_option['wp_set_ids'])
            ];
        }

        $rental_set_option_relations_sql = '';
        $setmeta_sql = [];
        $_option_ids = [];
        // grouping attached sets and categories based on option id
        foreach($attached_items_grouped as $option_id=>$items) {
            
            $set_wp_id_collection = [];
            // collecting wp set ids related to rental set ids for the current option
            if (!empty($items['sets'])) {
                foreach($set_ids as $sid) {
                    // for updated option
                    if ($updated_option_id == $option_id) {
                        if (in_array($sid["rental_id"], $items['sets'])) {
                            // collect sets grouped by rental set id
                            // suporting all divisions
                            $set_wp_id_collection[$sid["rental_id"]][] = $sid["id"];
                        }
                    } else {
                        // other options wp_ids are already known
                        // for other options
                        foreach($items['sets'] as $wp_id) {
                            if ($sid["id"] == $wp_id) {
                                $_option_ids[$wp_id][] = $option_id;
                            }
                        }
                    }
                }
            }

            // for updated option
            if ($updated_option_id == $option_id) {
                if (!empty($set_wp_id_collection)) {
                    // sql values of the option sets (type 1 = set)
                    foreach ($set_wp_id_collection as $rental_set_id => $wp_id_list) {
                        foreach($wp_id_list as $wp_id) {
                            $_option_ids[$wp_id][] = $option_id;
                            // set option relation sql
                            $rental_set_option_relations_sql .= empty($rental_set_option_relations_sql) ? "('$option_id', '$rental_set_id', '$wp_id')" : ",('$option_id', '$rental_set_id', '$wp_id')";
                        }
                    }
                }
            }

        }

        $wpdb->query($wpdb->prepare("DELETE FROM {$rental_set_option_relations} WHERE set_option_id = %d", $updated_option_id));
        $wpdb->query("INSERT INTO {$rental_set_option_relations} (`set_option_id`, `rental_id`, `wp_id`) VALUES " . $rental_set_option_relations_sql);

        // delete all set options postmeta
        $sql_delete = "DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_set_options'";
        $wpdb->query($sql_delete);
       
        // insert new relations
        foreach($_option_ids as $wp_id => $option_ids) {
            $option_ids_rearranged = array_values(array_unique($option_ids));
            $option_ids = json_encode($option_ids_rearranged);
            $setmeta_sql[$wp_id] = "($wp_id, '_set_options', '$option_ids')";
        }
        rental_insert("INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`) VALUES", $setmeta_sql);

    }


    public function create($created_option_id)
    {
        global $wpdb, $rental_tables;
        $rental_set_option_relations = $wpdb->prefix . $rental_tables["set_option_relations"];
        $rental_set_relations = $wpdb->prefix . $rental_tables["set_relations"];

        // collect every division's rental set ids
        $set_ids = $wpdb->get_results("SELECT id, rental_id FROM {$rental_set_relations}", ARRAY_A);

        $setmeta_sql = [];
        $attached_items_grouped = [];
        // adding updated option
        $attached_items_grouped[$created_option_id] = [
            'sets' => $this->details['sets_attached']
        ];

        $rental_set_option_relations_sql = '';
        $setmeta_sql = [];
        $_option_ids = [];
        // grouping attached sets and categories based on option id
        $set_wp_id_collection = [];
        // collecting wp set ids related to rental set ids for the current option
        if (!empty($attached_items_grouped[$created_option_id]['sets'])) {
            foreach($set_ids as $sid) {
                if (in_array($sid["rental_id"], $attached_items_grouped[$created_option_id]['sets'])) {
                    // collect sets grouped by rental set id
                    // suporting all divisions
                    $set_wp_id_collection[$sid["rental_id"]][] = $sid["id"];
                }
            }
        }

        // for updated option
        if (!empty($set_wp_id_collection)) {
            // sql values of the option sets (type 1 = set)
            foreach ($set_wp_id_collection as $rental_set_id => $wp_id_list) {
                foreach($wp_id_list as $wp_id) {
                    $_option_ids[$wp_id][] = $created_option_id;
                    // set option relation sql
                    $rental_set_option_relations_sql .= empty($rental_set_option_relations_sql) ? "('$created_option_id', '$rental_set_id', '$wp_id')" : ",('$created_option_id', '$rental_set_id', '$wp_id')";
                }
            }
        }

        $wpdb->query($wpdb->prepare("DELETE FROM {$rental_set_option_relations} WHERE set_option_id = %d", $created_option_id));
        $wpdb->query("INSERT INTO {$rental_set_option_relations} (`set_option_id`, `rental_id`, `wp_id`) VALUES " . $rental_set_option_relations_sql);

        $delete_postmeta_ids = [];
        foreach($_option_ids as $wp_id => $option_ids) {
            $sql = "SELECT * FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = '_set_options'";
            $existing_options = $wpdb->get_row($wpdb->prepare($sql, $wp_id), ARRAY_A);
            $existing_options_decoded = [];
            if (!empty($existing_options['meta_value'])) {
                // existing options update
                $existing_options_decoded = json_decode($existing_options['meta_value'], true);
                if (!empty($existing_options_decoded)) {
                    $existing_options_decoded[count($existing_options_decoded)+1] = $option_ids[0];
                } else {
                    $existing_options_decoded[0] = $option_ids[0];
                }
            } else {
                // existing options create
                $existing_options_decoded[0] = $option_ids[0];
            }

            $option_ids_rearranged = array_values(array_unique($existing_options_decoded));
            $option_ids_updated = json_encode($option_ids_rearranged);
            $setmeta_sql[$wp_id] = "($wp_id, '_set_options', '$option_ids_updated')";

            $delete_postmeta_ids[] = $wp_id;
        }

        $placeholders = array_fill(0, count($delete_postmeta_ids), '%d');
        $placeholders_format = implode(', ', $placeholders);
        // delete all set options postmeta with specified post(set) ids
        $sql_delete = "DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_set_options' AND post_id IN ({$placeholders_format})";
        $wpdb->query($wpdb->prepare($sql_delete, $delete_postmeta_ids));
        // insert updated postmeta values
        rental_insert("INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`) VALUES", $setmeta_sql);
    }

    /**
     * Delete a set_options.
     *
     * @return array
     */
    public function delete()
    {
        global $wpdb, $rental_tables;
        $rental_set_options = $wpdb->prefix . $rental_tables["set_options"];
        $rental_set_option_relations = $wpdb->prefix . $rental_tables["set_option_relations"];
        $setmeta_sql = [];

        $sql = "
            SELECT 
                options.*,
                GROUP_CONCAT(DISTINCT relation_sets.wp_id) wp_set_ids
            FROM 
                {$rental_set_options} as options
            LEFT JOIN {$rental_set_option_relations} as relation_sets ON relation_sets.set_option_id = options.id
            WHERE
                options.id = %d
            GROUP BY
                options.id
        ";
        $set_option = $wpdb->get_row($wpdb->prepare($sql, $this->id), ARRAY_A);


        $set_ids = explode(',',$set_option['wp_set_ids']);
        $set_ids = array_unique($set_ids);
        $delete_postmeta_ids = [];
        foreach($set_ids as $sid) {
            $sql = "SELECT * FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = '_set_options'";
            $existing_options = $wpdb->get_row($wpdb->prepare($sql, $sid), ARRAY_A);
            $existing_options_decoded = [];
            $updated_values = [];
            if (!empty($existing_options['meta_value'])) {
                // existing options update
                $existing_options_decoded = json_decode($existing_options['meta_value'], true);
                if (!empty($existing_options_decoded)) {
                    foreach($existing_options_decoded as $option_id) {
                        if ($this->id != $option_id) {
                            $updated_values[] = $option_id;
                        }
                    }
                }
            }

            if ($updated_values) {
                $option_ids_rearranged = array_values(array_unique($updated_values));
                $option_ids_updated = json_encode($option_ids_rearranged);
                $setmeta_sql[$sid] = "($sid, '_set_options', '$option_ids_updated')";
                $delete_postmeta_ids[] = $sid;
            }
        }

        if ($delete_postmeta_ids) {
            $placeholders = array_fill(0, count($delete_postmeta_ids), '%d');
            $placeholders_format = implode(', ', $placeholders);
            // delete all set options postmeta with specified post(set) ids
            $sql_delete = "DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_set_options' AND post_id IN ({$placeholders_format})";
            $wpdb->query($wpdb->prepare($sql_delete, $delete_postmeta_ids));
            // insert updated postmeta values
            rental_insert("INSERT INTO `$wpdb->postmeta` (`post_id`, `meta_key`, `meta_value`) VALUES", $setmeta_sql);
        }
        
        $result = (bool) $wpdb->delete($rental_set_options, [
            "id" => $this->id
        ]);
        if ($result) {
            // delete rental_set_options_relations
            $result2 = (bool) $wpdb->delete($rental_set_option_relations, [
                "set_option_id" => $this->id
            ]);
            if ($result2) {
                return $this->id;
            }
        }
        return false;
    }


}