<?php

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

class Niwa_AI_HTML_Content_Cleaner {

    const MIN_TEXT_LENGTH = 10;

    const ALLOWED_HTML_TAGS = array(
        'p',
        'h1',
        'h2',
        'h3',
        'h4',
        'h5',
        'h6',
        'li',
        'td',
        'th',
        'blockquote',
        'div',
        'span',
        'article',
        'section',
    );

    const REMOVE_SELECTORS = array(
        'nav',
        'header',
        'footer',
        '.navigation',
        '.nav',
        '.menu',
        '.sidebar',
        '.widget',
        'form',
        'select',
        'input',
        'button',
        '.woocommerce-shipping-calculator',
        '.cart-collaterals',
        '.checkout-form',
    );

    const WOOCOMMERCE_SYSTEM_PAGES = array(
        'cart',
        'checkout',
        'my-account',
        'order-tracking',
        'order-received',
    );

    /**
     * Clean HTML content using DOM-based extraction.
     *
     * @param string $html Raw HTML content.
     * @return string Cleaned text content.
     */
    public function clean( $html ) {
        if ( empty( $html ) ) {
            return '';
        }

        // Remove scripts, styles and form elements via regex first.
        $html = preg_replace( '/<script[^>]*>.*?<\/script>/is', '', $html );
        $html = preg_replace( '/<style[^>]*>.*?<\/style>/is', '', $html );
        $html = preg_replace( '/<select[^>]*>.*?<\/select>/is', '', $html );
        $html = preg_replace( '/<option[^>]*>.*?<\/option>/is', '', $html );
        $html = preg_replace( '/<textarea[^>]*>.*?<\/textarea>/is', '', $html );

        if ( ! class_exists( 'DOMDocument' ) ) {
            return $this->fallback_clean( $html );
        }

        $dom = new DOMDocument();
        // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
        @$dom->loadHTML(
            '<?xml encoding="UTF-8">' . $html,
            LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOERROR | LIBXML_NOWARNING
        );

        $xpath = new DOMXPath( $dom );

        // Remove noise elements by class/tag.
        foreach ( self::REMOVE_SELECTORS as $selector ) {
            $clean_selector = trim( $selector, '.' );
            $query          = "//*[contains(@class, '{$clean_selector}')] | //{$clean_selector}";
            $nodes          = $xpath->query( $query );

            if ( $nodes ) {
                foreach ( $nodes as $node ) {
                    if ( $node->parentNode ) {
                        $node->parentNode->removeChild( $node );
                    }
                }
            }
        }

        // Remove form-related elements by tag name.
        $form_tags = array( 'form', 'select', 'option', 'input', 'button', 'textarea', 'label' );
        foreach ( $form_tags as $tag ) {
            $elements = $dom->getElementsByTagName( $tag );
            for ( $i = $elements->length - 1; $i >= 0; $i-- ) {
                $element = $elements->item( $i );
                if ( $element && $element->parentNode ) {
                    $element->parentNode->removeChild( $element );
                }
            }
        }

        // Extract text from allowed elements.
        $text_parts = array();

        foreach ( self::ALLOWED_HTML_TAGS as $tag ) {
            $elements = $dom->getElementsByTagName( $tag );
            foreach ( $elements as $element ) {
                $text = trim( $element->textContent );
                if ( $text && strlen( $text ) > self::MIN_TEXT_LENGTH ) {
                    if ( $this->looks_like_country_list( $text ) ) {
                        continue;
                    }
                    $text_parts[] = $text;
                }
            }
        }

        // If no structured content found, fallback to strip_tags.
        if ( empty( $text_parts ) ) {
            return $this->fallback_clean( $html );
        }

        $text_parts = array_unique( $text_parts );
        return implode( "\n", $text_parts );
    }

    /**
     * Check if a post should be skipped during indexing.
     *
     * @param WP_Post $post The post object.
     * @return bool True if the post should be skipped.
     */
    public function should_skip_post( $post ) {
        if ( ! $post || ! is_object( $post ) ) {
            return true;
        }

        // Skip WooCommerce system pages.
        if ( 'page' === $post->post_type ) {
            $slug = isset( $post->post_name ) ? (string) $post->post_name : '';
            if ( in_array( $slug, self::WOOCOMMERCE_SYSTEM_PAGES, true ) ) {
                return true;
            }
        }

        // Skip posts marked with _za_noindex.
        $noindex = get_post_meta( $post->ID, '_za_noindex', true );
        if ( ! empty( $noindex ) ) {
            if ( 'product' === (string) $post->post_type && $this->is_product_indexable_despite_noindex( $post ) ) {
                return false;
            }
            return true;
        }

        return false;
    }

    private function is_product_indexable_despite_noindex( $post ) {
        if ( ! $post || ! is_object( $post ) || 'publish' !== (string) $post->post_status ) {
            return false;
        }

        return 'outofstock' !== $this->get_effective_product_stock_status( intval( $post->ID ) );
    }

    private function get_effective_product_stock_status( $product_id ) {
        $product_id = intval( $product_id );
        if ( $product_id <= 0 ) {
            return 'outofstock';
        }

        if ( function_exists( 'wc_get_product' ) ) {
            $product = wc_get_product( $product_id );
            if ( $product && method_exists( $product, 'is_type' ) && $product->is_type( 'variable' ) && method_exists( $product, 'get_children' ) ) {
                foreach ( (array) $product->get_children() as $variation_id ) {
                    $variation = wc_get_product( intval( $variation_id ) );
                    if ( ! $variation || ! method_exists( $variation, 'is_type' ) || ! $variation->is_type( 'variation' ) ) {
                        continue;
                    }
                    if ( method_exists( $variation, 'get_status' ) && ! in_array( (string) $variation->get_status(), array( 'publish', 'private' ), true ) ) {
                        continue;
                    }
                    if ( method_exists( $variation, 'is_in_stock' ) && $variation->is_in_stock() ) {
                        return 'instock';
                    }
                    if ( method_exists( $variation, 'get_stock_status' ) && 'outofstock' !== (string) $variation->get_stock_status() ) {
                        return (string) $variation->get_stock_status();
                    }
                }

                return 'outofstock';
            }

            if ( $product && method_exists( $product, 'get_stock_status' ) ) {
                return (string) $product->get_stock_status();
            }
        }

        $stock_status = (string) get_post_meta( $product_id, '_stock_status', true );
        return '' !== $stock_status ? $stock_status : 'instock';
    }

    /**
     * Fallback cleaning when DOMDocument is unavailable or DOM extraction is empty.
     *
     * @param string $html HTML content.
     * @return string Cleaned text.
     */
    private function fallback_clean( $html ) {
        $stripped = trim( wp_strip_all_tags( $html ) );
        if ( $this->looks_like_country_list( $stripped ) ) {
            return '';
        }
        return $stripped;
    }

    /**
     * Check if text looks like a country dropdown list.
     *
     * @param string $text Text to check.
     * @return bool True if text looks like country list.
     */
    private function looks_like_country_list( $text ) {
        $country_indicators = array(
            'Afghanistan',
            'Australia',
            'Austria',
            'Albanija',
            'United States',
            'United Kingdom',
            'Germany',
            'France',
        );

        $count = 0;
        foreach ( $country_indicators as $indicator ) {
            if ( false !== mb_stripos( $text, $indicator ) ) {
                $count++;
            }
            if ( $count >= 5 ) {
                return true;
            }
        }

        if ( strlen( $text ) > 2000 && substr_count( $text, ',' ) > 50 ) {
            return true;
        }

        return false;
    }
}
