<?php
// phpcs:ignoreFile
namespace WooSwatches;

use function WooSwatchesPro\is_license_valid;

class Product_Swatches {

    protected $general_settings;
    protected $advanced_settings;
    protected $all_settings;

    public function __construct() {
        add_action( 'plugins_loaded', [ $this, 'get_mod_settings' ] );
        add_filter( 'woocommerce_dropdown_variation_attribute_options_html', [ $this, 'replace_existing_field' ], 20, 2 );
        add_action( 'wp_ajax_get_product_variations', [ $this, 'get_product_variations' ] );
        add_action( 'wp_ajax_nopriv_get_product_variations', [ $this, 'get_product_variations' ] );
    }

    public function get_product_variations() {

        $product_ids = $_GET['product_ids'] ?: [];

        if ( empty($product_ids) ) wp_send_json_error( 'Product id not found' );

        if ( ! is_array( $product_ids ) ) $product_ids = [ $product_ids ];

        $product_variations = [];

        add_filter( 'woocommerce_hide_invisible_variations', '__return_false' );
        
        foreach ( $product_ids as $product_id ) {

            $product_id = absint( $product_id );
            
            $product = wc_get_product( $product_id );

            if ( empty($product) ) continue;
            
            if ( 'variable' === $product->get_type() ) {
                $product_variations[ $product_id ] = $product->get_available_variations();
            }
            
        }
        
        remove_filter( 'woocommerce_hide_invisible_variations', '__return_false' );

        wp_send_json_success( $product_variations );

    }

    public function get_mod_settings() {
        $this->general_settings = plugin()->modules->get_module_settings('general-settings');
        $this->advanced_settings = plugin()->modules->get_module_settings('advanced-settings');
    }

    public function replace_existing_field( $html, $args ) {

        $args = wp_parse_args( apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'dropdown_variation_attr_options', $args ), array(
            'options'          => false,
            'attribute'        => false,
            'product'          => false,
            'selected'         => false,
            'name'             => '',
            'id'               => '',
            'class'            => '',
            'show_option_none' => esc_html__('Choose an option', 'gs-woo-variation'),
            'is_archive'       => false
        ));

        $this->all_settings = Helpers::get_product_settings_for_display( get_the_ID() );

        if ( $args['is_archive'] ) {
            return $this->archive_product_page( $html, $args );
        } else {
            return $this->single_product_page( $html, $args );
        }
    }

    public function archive_product_page( $html, $args ) {
        return $html;
    }

    public function single_product_page($html, $args) {

        $product = $args['product'];
        
        /*
         * Return $html if it is excluded
         */
        $category_ids = $product->get_category_ids();
        $exclude_cats = $this->advanced_settings['exclude_cat'];
        $is_excluded = array_intersect( $exclude_cats, $category_ids );
        if ( ! empty($is_excluded) ) return $html;

        /*
         * Add Variation Content
         */
        if ( false === $args['selected'] && $args['attribute'] && $args['product'] instanceof \WC_Product ) {
            $selected_key = 'attribute_' . sanitize_title($args['attribute']);
            $args['selected'] = isset($_REQUEST[$selected_key]) ? wc_clean(wp_unslash($_REQUEST[$selected_key])) : $args['product']->get_variation_default_attribute($args['attribute']);
        }

        $options               = $args['options'];
        $attribute             = $args['attribute'];
        $name                  = $args['name'] ? $args['name'] : wc_variation_attribute_name($attribute);
        $id                    = $args['id'] ? $args['id'] : sanitize_title($attribute);
        $class                 = $args['class'];
        $show_option_none      = (bool) $args['show_option_none'];
        $show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : esc_html__('Choose an option', 'gs-woo-variation');

        if ( empty($options) && !empty($product) && !empty($attribute) ) {
            $attributes = $product->get_variation_attributes();
            $options    = $attributes[$attribute];
        }

        // Actual Settings
        $dropdown_to_button = (bool) $this->all_settings['dropdown_to_button'];

        $get_attr           = Helpers::get_attribute_taxonomy( $attribute );
        $attribute_types    = array_keys( Helpers::select_attr_types() );
        $attribute_type     = ($get_attr) ? $get_attr->attribute_type : 'select';
        $swatches_data      = array();

        if ( ! in_array( $attribute_type, $attribute_types) ) return $html;
        
        if ( $dropdown_to_button && $attribute_type === 'select' ) {
            $attribute_type = 'button';
        }
        
        $select_inline_style = '';
        if ( $attribute_type !== 'select' ) {
            $select_inline_style  = 'style="display:none"';
            $class               .= ' woo-variation-raw-select';
        }

        $html = '<select ' . $select_inline_style . ' id="' . esc_attr($id) . '" class="' . esc_attr($class) . '" name="' . esc_attr($name) . '" data-attribute_name="' . esc_attr( wc_variation_attribute_name($attribute) ) . '" data-show_option_none="' . ($show_option_none ? 'yes' : 'no') . '">';
        $html .= '<option value="">' . esc_html($show_option_none_text) . '</option>';

        if ( !empty($options) ) {
            if ( $product && taxonomy_exists($attribute) ) {
                
                $terms = wc_get_product_terms($product->get_id(), $attribute, array(
                    'fields' => 'all'
                ));

                foreach ($terms as $term) {
                    if (in_array($term->slug, $options, true)) {
                        $swatches_data[] = $this->get_swatch_data($args, $term);
                       
                        $html .= '<option value="' . esc_attr($term->slug) . '" ' . selected(sanitize_title($args['selected']), $term->slug, false) . '>' . esc_html(apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'variation_option_name', $term->name, $term, $attribute, $product)) . '</option>';
                    }
                }
            } else {
                foreach ($options as $option) {
                    // This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
                    $selected = sanitize_title( $args['selected']) === $args['selected'] ? selected($args['selected'], sanitize_title($option), false) : selected($args['selected'], $option, false );

                    $swatches_data[] = $this->get_swatch_data($args, $option);

                    $html .= '<option value="' . esc_attr($option) . '" ' . $selected . '>' . esc_html(apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'variation_option_name', $option, null, $attribute, $product)) . '</option>';
                }
            }
        }

        $html .= '</select>';

        if ( $attribute_type === 'select' ) {
            return $html;
        }

        $item        = '';
        $wrapper     = '';
        $wrapper_end = '';

        if ( !empty($options) && !empty($swatches_data) && $product ) {
                    
            $wrapper         = $this->wrapper_start( $args, $attribute, $product, $attribute_type, $options );
            $_attribute_type = $attribute_type;

            foreach ( $swatches_data as $data ) {

                $attribute_type = $_attribute_type;
                
                if ( 'image' === $attribute_type && !is_array($this->get_image_attribute($data, $attribute_type)) ) {
                    $attribute_type = 'button';
                }

                $item .= $this->item_start( $data, $attribute_type );

                $item .= $this->color_attribute( $data, $attribute_type );
                $item .= $this->image_attribute( $data, $attribute_type );
                $item .= $this->button_attribute( $data, $attribute_type );
                $item .= $this->radio_attribute( $data, $attribute_type );

                $item .= $this->item_end();
            }

            $wrapper_end = $this->wrapper_end();
        }

        $html .= $wrapper . $item . $wrapper_end;

        return apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'disable_variations_html', $html, $args, $swatches_data, $this );

    }

    public function wrapper_html_attribute( $args, $attribute, $product, $attribute_type, $options ) {

        $raw_html_attributes = array();
        $css_classes         = $this->wrapper_class( $args, $attribute, $product, $attribute_type );

        $raw_html_attributes['role']                  = 'radiogroup';
        $raw_html_attributes['aria-label']            = wc_attribute_label( $attribute, $product );
        $raw_html_attributes['class']                 = implode( ' ', array_unique( array_values( $css_classes ) ) );
        $raw_html_attributes['data-attribute_name']   = wc_variation_attribute_name( $attribute );
        $raw_html_attributes['data-attribute_values'] = wc_esc_json( wp_json_encode( array_values( $options ) ) );
        $raw_html_attributes['style']                 = 'display: none;';

        return $raw_html_attributes;
    }

    public function wrapper_start( $args, $attribute, $product, $attribute_type, $options ) {
                
        $html_attributes = $this->wrapper_html_attribute( $args, $attribute, $product, $attribute_type, $options );
        
       return sprintf( '<ul %s>', wc_implode_html_attributes( $html_attributes ) );
    }

    public function get_swatch_data( $args, $term_or_option ) {

        $options   = $args['options'];
        $product   = $args['product'];
        $attribute = $args['attribute'];

        $is_term = is_object($term_or_option);

        if ($is_term) {
            $term        = $term_or_option;
            $slug        = $term->slug;
            $is_selected = (sanitize_title($args['selected']) === $term->slug);
            $option_name = apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'variation_option_name', $term->name, $term, $attribute, $product );
        } else {
            $option      = $slug = $term_or_option;
            $is_selected = (sanitize_title($args['selected']) === $args['selected']) ? ($args['selected'] === sanitize_title($option)) : ($args['selected'] === $option);
            $option_name = apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'variation_option_name', $option, null, $attribute, $product );
        }

        return array(
            'is_archive'      => isset($args['is_archive']) ? $args['is_archive'] : false,
            'is_selected'     => $is_selected,
            'is_term'         => $is_term,
            'term_id'         => $is_term ? $term->term_id : Helpers::sanitize_name($option),
            'slug'            => $slug,
            'option_slug'     => Helpers::sanitize_name($slug),
            'item'            => $term_or_option,
            'options'         => $options,
            'option_name'     => $option_name,
            'attribute'       => $attribute,
            'attribute_key'   => sanitize_title($attribute),
            'attribute_name'  => wc_variation_attribute_name($attribute),
            'attribute_label' => wc_attribute_label($attribute, $product),
            'args'            => $args,
            'product'         => $product,
        );
    }

    public function get_attribute_type( $data, $variation_data = array() ) {
                                
        $args = $data[ 'args' ];
        
        $product        = $args[ 'product' ];
        $attribute_name = $data[ 'attribute_name' ];
        $term_id        = $data[ 'term_id' ];
        $slug           = $data[ 'slug' ];
        
        
        // Product label Option
        
        $product_attribute_type = woo_variation_swatches()->get_product_settings( $product, $data[ 'attribute_key' ], 'terms', $data[ 'term_id' ], 'type' );
        
        $attribute_label_type = woo_variation_swatches()->get_product_settings( $product, $data[ 'attribute_key' ], 'type' );
        
        if ( 'select' === $attribute_label_type ) {
            $product_attribute_type = false;
        }
        
        // Global Option
        
        if ( ! empty( $variation_data ) && isset( $variation_data[ $attribute_name ] ) && isset( $variation_data[ $attribute_name ][ $slug ] ) ) {
            $attribute_type = $variation_data[ $attribute_name ][ $slug ][ 'type' ];
        } else {
            $attribute_type = 'button';
        }
        
        return empty( $product_attribute_type ) ? $attribute_type : $product_attribute_type;
    }

    public function color_attribute( $data, $attr_type ) {

        // Color
        if ( 'color' === $attr_type ) {
            $term = $data[ 'item' ];
            $primary_color = sanitize_hex_color( Helpers::get_product_attr_color( $term ) );
            $html = sprintf( '<span class="variable-item-span variable-item-span-color" style="background-color:%s;"></span>', esc_attr( $primary_color ) );
            return apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'color_attr_output', $html, $data );
        }

    }

    public function image_attribute( $data, $attribute_type, $variation_data = array() ) {
        if ( 'image' === $attribute_type ) {

            $option_name = $data['option_name'];

            // Global
            $image = $this->get_image_attribute($data, $attribute_type, $variation_data);

            $image = sprintf('<img class="variable-item-image" aria-hidden="true" alt="%s" src="%s" width="%d" height="%d" />', esc_attr($option_name), esc_url($image[0]), esc_attr($image[1]), esc_attr($image[2]));

            if ( $this->all_settings['image_field_style'] == 'style_two' && !empty( $data['option_name'] ) ) {
                $image .= '<span class="variable-item-span">' . $data['option_name'] . '</span>';
            }

            return $image;

        }
    }

    public function button_attribute( $data, $attribute_type ) {

        if ('button' === $attribute_type) {
            $option_name = $data['option_name'];
            return sprintf('<span class="variable-item-span variable-item-span-button">%s</span>', esc_html($option_name));
        }
    }

    public function radio_attribute( $data, $attribute_type ) {

        if ('radio' === $attribute_type) {

            $attribute_name = $data['attribute_name'];
            $product        = $data['product'];
            $attributes     = $product->get_variation_attributes();
            $slug           = $data['slug'];
            $is_selected    = wc_string_to_bool($data['is_selected']);
            $option_name    = $data['option_name'];

            $name            = sprintf('gs_radio_%s', $attribute_name);
            $attribute_value = $slug;

            $label          = esc_html($option_name);
            $label_template = apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'global_item_radio_label_template', '%image% - %variation% - %price% %stock%', $data);

            return sprintf('<label class="variable-item-radio-input-wrapper"><span class="variable-item-radio-circle"></span><span class="variable-item-radio-value-wrapper">%4$s</span></label>', $name, checked($is_selected, true, false), esc_attr($slug), $label);
        }
    }

    public function item_start( $data, $attr_type ) {

        $args           = $data['args'];
        $term_or_option = $data['item'];
        $options        = $args['options'];
        $product        = $args['product'];
        $attribute      = $args['attribute'];
        $is_selected    = $data['is_selected'];
        $option_name    = $data['option_name'];
        $option_slug    = $data['option_slug'];
        $slug           = $data['slug'];

        $is_term = wc_string_to_bool($data['is_term']);

        $css_class = implode(' ', array_unique( array_values( apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'variable_item_css_class', $this->get_css_classes($data), $data ) ) ) );

        $html_attributes = array(
            'aria-checked' => ($is_selected ? 'true' : 'false'),
            'tabindex'     => (wp_is_mobile() ? '2' : '0'),
        );

        $html_attributes = wp_parse_args($this->get_tooltip_attribute($data), $html_attributes);

        $html_attributes = apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'variable_item_custom_attr', $html_attributes, $attr_type, $data);

        return sprintf('<li %1$s class="variable-item %2$s-variable-item %2$s-variable-item-%3$s %4$s" title="%5$s" data-title="%5$s" data-value="%6$s" role="radio" tabindex="0"><svg class="gswps--icon gswps--tick" xmlns="http://www.w3.org/2000/svg" width="16" height="12" viewBox="0 0 16 12" fill="var(--gs-wvs--tick-color, #000)"><use href="#gs-wvs--tick" /></svg><svg class="gswps--icon gswps--close" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="var(--gs-wvs--close-color, #000)"><use href="#gs-wvs--close" /></svg><div class="variable-item-contents">', wc_implode_html_attributes($html_attributes), esc_attr($attr_type), esc_attr($option_slug), esc_attr($css_class), esc_html($option_name), esc_attr($slug));
    }

    public function item_end() {
        $html = '';
        if ($this->advanced_settings['disable_out_of_stock']) {
            $html .= '<div class="gs-stock-left-info" data-gs-stock-info=""></div>';
        }
        $html .= '</div></li>';

        return $html;
    }

    public function get_css_classes( $data ) {

        $css_classes = array();

        $is_selected = wc_string_to_bool( $data['is_selected'] );

        if ($is_selected) {
            $css_classes[] = 'selected';
        }

        return $css_classes;
    }

    public function get_tooltip_attribute( $data ) {

        $html_attributes = array();

        $option_name = $data['option_name'];

        $enable_tooltip = $this->general_settings['enable_tooltip'];

        if ( $enable_tooltip ) {
            $tooltip = trim( apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'global_variable_item_tooltip_text', $option_name, $data));
            $html_attributes['data-gstooltip'] = esc_attr($tooltip);
        }

        return $html_attributes;
    }

    public function wrapper_intro( $args, $attribute, $product, $attr_type, $options ) {

        $html_attributes = $this->wrapper_attr( $args, $attribute, $product, $attr_type, $options );

        return sprintf('<ul %s>', wc_implode_html_attributes($html_attributes));
    }

    public function wrapper_attr( $args, $attribute, $product, $attribute_type, $options ) {

        $raw_html_attributes = array();
        $css_classes         = $this->wrapper_class($args, $attribute, $product, $attribute_type);

        $raw_html_attributes['role']                  = 'radiogroup';
        $raw_html_attributes['aria-label']            = wc_attribute_label($attribute, $product);
        $raw_html_attributes['class']                 = implode(' ', array_unique(array_values($css_classes)));
        $raw_html_attributes['data-attribute_name']   = wc_variation_attribute_name($attribute);
        $raw_html_attributes['data-attribute_values'] = wc_esc_json(wp_json_encode(array_values($options)));

        return $raw_html_attributes;
    }

    public function wrapper_class( $args, $attribute, $product, $attribute_type ) {

        $classes = array();

        if ( $attribute_type === 'color' ) {
            $classes[] = sprintf('gs-field-style-%s', $this->all_settings['color_field_style']);
            $classes[] = sprintf('gs-shape-style-%s', $this->all_settings['color_shape_style']);
        }

        if ( $attribute_type === 'image' ) {
            $classes[] = sprintf('gs-field-style-%s', $this->all_settings['image_field_style']);
            $classes[] = sprintf('gs-shape-style-%s', $this->all_settings['image_shape_style']);
        }

        if ( $attribute_type === 'button' ) {
            $classes[] = sprintf('gs-field-style-%s', $this->all_settings['button_field_style']);
            $classes[] = sprintf('gs-shape-style-%s', $this->all_settings['button_shape_style']);
        }

        $classes[] = 'gs-variable-items-wrapper';
        $classes[] = sprintf('%s-variable-items-wrapper', $attribute_type);

        return $classes;
    }

    public function wrapper_end() {
        return '</ul>';
    }

    public function get_image_attribute( $data, $attr_type ) {
        if ( 'image' === $attr_type ) {

            $term = $data['item'];

            $attachment_id = apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'attribute_image_id', absint(Helpers::get_product_attr_image($term, $data)), $data);
            $image_size    = apply_filters( GS_WOO_SWATCHES_HOOK_PREFIX . 'attribute_image_size', sanitize_text_field($this->advanced_settings['attr_img_size']));

            return wp_get_attachment_image_src($attachment_id, $image_size);
        }
    }

    public function get_variation_data_by_attribute_name( $available_variations, $attribute_name ) {

        $assigned       = array();
        $attribute_name = wc_variation_attribute_name($attribute_name);

        foreach ($available_variations as $variation) {
            $attrs = $variation['attributes'];
            $value = $attrs[$attribute_name];

            if ( !isset($assigned[$attribute_name][$value]) && !empty($value) ) {
                $assigned[$attribute_name][$value] = array(
                    'image_id'     => $variation['variation_image_id'],
                    'variation_id' => $variation['variation_id'],
                    'type'         => empty($variation['variation_image_id']) ? 'button' : 'image',
                );
            }
        }

        return $assigned;
    }
    
}
