<?php
/**
 * Smart Auto-Linker v4 — TF-IDF Cosine Similarity (ported from Python)
 *
 * Architecture (matches the Python internal_linker.py):
 *   1. REPAIR  — Fix any legacy broken links pointing to /blog/
 *   2. FILTER  — Blocklist: hub pages, categories, tags, query strings
 *   3. PER-PARAGRAPH RANKING — TF-IDF cosine similarity between
 *      paragraph text and URL slug words (slug words are boosted 3x)
 *   4. INJECT  — Place the best-matching link into each paragraph
 *      (max 1 link per paragraph, strict minimum threshold)
 *   5. COUNTRY LINKING — "Doing business in…" pages
 *
 * Key improvements over v3:
 *   - Per-paragraph scoring (not global) — each paragraph gets its best match
 *   - TF-IDF cosine similarity (not simple word overlap)
 *   - URL slug words are boosted (repeated 3x in the document vector)
 *   - Hard minimum similarity threshold — weak matches are killed
 *   - Max 1 link per paragraph — prevents cluttering
 *   - URL blocklist — no blog hub, category, tag, author pages
 */
class DBA_Auto_Linker {

    private static $instance = null;

    /* ── Config (mirrors Python script constants) ── */
    const MIN_SIMILARITY       = 0.12;
    const MAX_LINKS_PER_POST   = 8;
    const MAX_LINKS_PER_PARA   = 1;
    const MIN_PARAGRAPH_CHARS  = 140;
    const SLUG_BOOST_REPEATS   = 3;

    /* ── URL patterns that must never be injected ── */
    private $block_patterns = array(
        '#/blog/?$#i',
        '#/category/#i',
        '#/tag/#i',
        '#/author/#i',
        '#/page/\d+/?$#i',
        '#/feed/?$#i',
        '#/wp-json/#i',
        '#/wp-admin/#i',
        '#/wp-content/#i',
        '#/xmlrpc\.php#i',
        '#/lets-connect/?$#i',
    );

    private $block_exact = array(
        'https://www.damalion.com/blog',
        'https://www.damalion.com/blog/',
        'https://www.damalion.com',
        'https://www.damalion.com/',
    );

    /* ── Noise words (zero topic signal) ── */
    private $noise_words = array(
        'the','and','for','with','from','this','that','into','about','also',
        'how','what','why','when','where','are','was','were','been','have','has',
        'will','can','may','should','would','could','its','our','your','their',
        'a','an','in','on','at','to','of','by','as','is','it','or','be','do','no',
        'not','but','all','more','some','such','than','too','very','just',
        'set','up','per','via','use','new','way','get','let','try','run','put',
        'see','own','out','off','yet','so','if','my','we','he','she','they',
        'these','those','which','who','whom','each','every','both','other',
        'make','made','like','many','much','well','most','only','over','must',
        'here','there','then','now','them','been','being','does','did','had',
        'two','one','first','last','next','after','before','between','through',
        'under','while','during','without','within','among','across','along',
    );

    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /* ================================================================
     *  MAIN ENTRY POINT — inject_links()
     *  Public API unchanged from v3.
     * ================================================================ */

    public function inject_links( $html, $pillar_url = '', $satellite_urls = array(), $subject = '', $theme = '', $max_links = 8, $title = '', $category = '' ) {

        if ( empty( $html ) || strlen( $html ) < 200 ) {
            return $html;
        }

        try {
            $sitemap = DBA_Sitemap::get_instance();
            $full_registry = $sitemap->get_full_registry();
        } catch ( \Throwable $e ) {
            error_log( 'DBA Auto-Linker: Failed to get registry: ' . $e->getMessage() );
            return $html;
        }

        if ( empty( $full_registry ) || ! is_array( $full_registry ) ) {
            error_log( 'DBA Auto-Linker: Full registry empty — skipping' );
            return $html;
        }

        // PHASE 1: REPAIR broken /blog/ links
        $html = $this->repair_broken_links( $html, $full_registry );

        // PHASE 2: BUILD CANDIDATE POOL (filter blocked URLs)
        $skip_urls = $this->build_skip_list( $html, $pillar_url, $satellite_urls );
        $candidates = $this->build_candidate_pool( $full_registry, $skip_urls );

        if ( empty( $candidates ) ) {
            error_log( 'DBA Auto-Linker: No candidates after filtering' );
            return $html;
        }

        error_log( 'DBA Auto-Linker: ' . count( $candidates ) . ' candidate pages after filtering' );

        // Load IDF weights
        $idf_weights = get_option( 'dba_idf_weights', array() );

        // PHASE 3+4: PER-PARAGRAPH TF-IDF RANKING + INJECTION
        $html = $this->inject_per_paragraph(
            $html,
            $candidates,
            $idf_weights,
            min( $max_links, self::MAX_LINKS_PER_POST ),
            $title,
            $subject,
            $theme,
            $category
        );

        return $html;
    }

    /* ================================================================
     *  PHASE 2: CANDIDATE POOL — filter blocked URLs
     * ================================================================ */

    private function is_blocked( $url ) {
        $url_clean = strtolower( rtrim( $url, '/' ) );

        foreach ( $this->block_exact as $blocked ) {
            if ( $url_clean === strtolower( rtrim( $blocked, '/' ) ) ) {
                return true;
            }
        }

        if ( strpos( $url, '?' ) !== false ) {
            $parsed = wp_parse_url( $url );
            $query = isset( $parsed['query'] ) ? $parsed['query'] : '';
            if ( ! preg_match( '/^lang=[a-z]{2,5}(-[a-z]{2,5})?$/i', $query ) ) {
                return true;
            }
        }

        foreach ( $this->block_patterns as $pattern ) {
            if ( preg_match( $pattern, $url ) ) {
                return true;
            }
        }

        return false;
    }

    private function build_skip_list( $html, $pillar_url, $satellite_urls ) {
        $skip = $this->extract_existing_urls( $html );
        $skip[] = strtolower( rtrim( $pillar_url, '/' ) );
        foreach ( $satellite_urls as $su ) {
            $url = is_array( $su ) ? ( isset( $su['url'] ) ? $su['url'] : '' ) : $su;
            if ( ! empty( $url ) ) {
                $skip[] = strtolower( rtrim( $url, '/' ) );
            }
        }
        $skip[] = 'https://www.damalion.com/lets-connect';
        $skip[] = 'https://www.damalion.com/blog';
        return array_unique( $skip );
    }

    private function build_candidate_pool( $registry, $skip_urls ) {
        $candidates = array();
        foreach ( $registry as $page ) {
            $url_lower = strtolower( rtrim( $page['url'], '/' ) );
            if ( in_array( $url_lower, $skip_urls ) ) continue;
            if ( $this->is_blocked( $page['url'] ) ) continue;
            $slug = isset( $page['slug'] ) ? $page['slug'] : '';
            if ( strlen( $slug ) < 4 ) continue;
            $candidates[] = $page;
        }
        return $candidates;
    }

    /* ================================================================
     *  PHASE 3+4: PER-PARAGRAPH TF-IDF COSINE RANKING + INJECTION
     *
     *  Ported from Python: rank_urls_for_paragraph() + inject_internal_links()
     *  Each paragraph is scored independently against all candidate URLs.
     *  Best match above threshold gets injected (max 1 per paragraph).
     * ================================================================ */

    private function inject_per_paragraph( $html, $candidates, $idf_weights, $max_links, $title, $subject, $theme, $category ) {

        // Pre-compute boosted slug-word arrays for each candidate (once)
        $candidate_docs = array();
        foreach ( $candidates as $idx => $page ) {
            $slug_words = $this->slug_words_from_url( $page['url'] );
            $title_words = $this->tokenize( strtolower( isset( $page['title'] ) ? $page['title'] : '' ) );
            // Boost slug words by repeating them (Python: SLUG_BOOST_REPEATS = 3)
            $doc_words = $title_words;
            for ( $r = 0; $r < self::SLUG_BOOST_REPEATS; $r++ ) {
                $doc_words = array_merge( $doc_words, $slug_words );
            }
            $candidate_docs[ $idx ] = $doc_words;
        }

        // Build IDF from candidates if stored IDF is empty
        $merged_idf = $idf_weights;
        if ( empty( $merged_idf ) ) {
            $merged_idf = $this->compute_idf( $candidate_docs );
        }

        // Context boost words from title/subject/theme/category
        $context_boost = $this->tokenize( strtolower( $title . ' ' . $subject . ' ' . $theme . ' ' . $category ) );

        $used_urls = array();
        $total_injected = 0;

        // Process paragraph by paragraph
        $self = $this; // PHP 5.4+ closure compat
        $result = preg_replace_callback( '/<p[^>]*>(.*?)<\/p>/si', function( $match ) use (
            $self, $candidates, $candidate_docs, $merged_idf, $context_boost,
            $max_links, &$used_urls, &$total_injected
        ) {
            $full_tag = $match[0];
            $para_content = $match[1];

            if ( $total_injected >= $max_links ) return $full_tag;

            $plain = wp_strip_all_tags( $para_content );
            if ( strlen( $plain ) < DBA_Auto_Linker::MIN_PARAGRAPH_CHARS ) return $full_tag;

            // Skip CTA paragraphs
            if ( strpos( $para_content, 'lets-connect' ) !== false ) return $full_tag;
            if ( strpos( $para_content, 'Damalion experts' ) !== false ) return $full_tag;
            if ( strpos( $para_content, 'contact your' ) !== false ) return $full_tag;

            // Skip paragraphs that already have a damalion.com link
            if ( preg_match( '/href=["\']https?:\/\/(?:www\.)?damalion\.com/i', $para_content ) ) return $full_tag;

            $para_words = $self->tokenize( strtolower( $plain ) );
            if ( count( $para_words ) < 5 ) return $full_tag;

            $query_words = array_merge( $para_words, $context_boost );

            // Score each candidate against this paragraph
            $scores = array();
            foreach ( $candidate_docs as $idx => $doc_words ) {
                $url_lower = strtolower( rtrim( $candidates[ $idx ]['url'], '/' ) );
                if ( in_array( $url_lower, $used_urls ) ) continue;

                $sim = $self->tfidf_cosine( $query_words, $doc_words, $merged_idf );
                if ( $sim >= DBA_Auto_Linker::MIN_SIMILARITY ) {
                    $scores[] = array( 'idx' => $idx, 'score' => $sim );
                }
            }

            if ( empty( $scores ) ) return $full_tag;

            usort( $scores, function( $a, $b ) {
                if ( abs( $b['score'] - $a['score'] ) < 0.001 ) return 0;
                return ( $b['score'] > $a['score'] ) ? 1 : -1;
            } );

            $plain_lower = strtolower( $plain );

            foreach ( $scores as $entry ) {
                $page = $candidates[ $entry['idx'] ];
                $anchor_info = $self->find_best_anchor( $page, $plain_lower );

                if ( empty( $anchor_info['text'] ) || strlen( $anchor_info['text'] ) < 4 ) continue;

                $new_tag = $self->inject_link_in_para(
                    $full_tag,
                    $anchor_info['text'],
                    $page['url'],
                    isset( $page['title'] ) ? $page['title'] : ''
                );

                if ( $new_tag !== $full_tag ) {
                    $full_tag = $new_tag;
                    $used_urls[] = strtolower( rtrim( $page['url'], '/' ) );
                    $total_injected++;
                    error_log( sprintf(
                        'DBA Auto-Linker: [%d] "%s" -> %s (cosine: %.3f)',
                        $total_injected,
                        $anchor_info['text'],
                        $page['url'],
                        $entry['score']
                    ) );
                    break; // 1 link per paragraph
                }
            }

            return $full_tag;
        }, $html );

        error_log( 'DBA Auto-Linker: Injected ' . $total_injected . ' contextual inbound links (TF-IDF cosine)' );
        return ( $result !== null ) ? $result : $html;
    }

    /* ================================================================
     *  TF-IDF COSINE SIMILARITY (ported from Python sklearn logic)
     * ================================================================ */

    public function tfidf_cosine( $query_words, $doc_words, $idf_weights ) {
        if ( empty( $query_words ) || empty( $doc_words ) ) return 0.0;

        $q_freq = array_count_values( $query_words );
        $d_freq = array_count_values( $doc_words );

        $shared_terms = array_intersect( array_keys( $q_freq ), array_keys( $d_freq ) );
        if ( empty( $shared_terms ) ) return 0.0;

        $dot = 0.0;
        $q_mag_sq = 0.0;
        $d_mag_sq = 0.0;

        foreach ( $q_freq as $term => $count ) {
            $idf = isset( $idf_weights[ $term ] ) ? $idf_weights[ $term ] : 1.0;
            $val = $count * $idf;
            $q_mag_sq += $val * $val;
        }

        foreach ( $d_freq as $term => $count ) {
            $idf = isset( $idf_weights[ $term ] ) ? $idf_weights[ $term ] : 1.0;
            $val = $count * $idf;
            $d_mag_sq += $val * $val;
        }

        foreach ( $shared_terms as $term ) {
            $idf = isset( $idf_weights[ $term ] ) ? $idf_weights[ $term ] : 1.0;
            $q_val = $q_freq[ $term ] * $idf;
            $d_val = $d_freq[ $term ] * $idf;
            $dot += $q_val * $d_val;
        }

        $q_mag = sqrt( $q_mag_sq );
        $d_mag = sqrt( $d_mag_sq );

        if ( $q_mag < 0.0001 || $d_mag < 0.0001 ) return 0.0;
        return $dot / ( $q_mag * $d_mag );
    }

    private function compute_idf( $candidate_docs ) {
        $doc_count = array();
        $total = max( count( $candidate_docs ), 1 );

        foreach ( $candidate_docs as $doc_words ) {
            $unique = array_unique( $doc_words );
            foreach ( $unique as $word ) {
                if ( ! isset( $doc_count[ $word ] ) ) $doc_count[ $word ] = 0;
                $doc_count[ $word ]++;
            }
        }

        $idf = array();
        foreach ( $doc_count as $word => $count ) {
            $idf[ $word ] = log( $total / max( $count, 1 ) ) + 1.0;
        }
        return $idf;
    }

    /* ================================================================
     *  TOKENIZATION
     * ================================================================ */

    public function tokenize( $text ) {
        $text = strtolower( $text );
        $words = preg_split( '/[^a-z0-9]+/', $text );
        $result = array();
        foreach ( $words as $w ) {
            if ( strlen( $w ) >= 3 && ! in_array( $w, $this->noise_words ) && ! is_numeric( $w ) ) {
                $result[] = $w;
            }
        }
        return $result;
    }

    public function slug_words_from_url( $url ) {
        $parsed = wp_parse_url( $url );
        $path = isset( $parsed['path'] ) ? trim( $parsed['path'], '/' ) : '';
        if ( empty( $path ) ) return array();
        $text = str_replace( array( '-', '_', '/' ), ' ', $path );
        return $this->tokenize( $text );
    }

    /* ================================================================
     *  ANCHOR SELECTION
     * ================================================================ */

    public function find_best_anchor( $page, $plain_lower ) {
        $best = array( 'text' => '', 'quality' => 0 );

        // Strategy 1: Try keyphrases from sitemap
        $keyphrases = isset( $page['keyphrases'] ) ? $page['keyphrases'] : array();
        if ( ! empty( $page['title'] ) ) {
            $keyphrases[] = $page['title'];
        }

        foreach ( $keyphrases as $phrase ) {
            $phrase_lower = strtolower( $phrase );
            if ( strlen( $phrase_lower ) < 4 ) continue;
            if ( strpos( $plain_lower, $phrase_lower ) === false ) continue;

            $word_count = str_word_count( $phrase );
            if ( $word_count >= 2 && $word_count <= 4 ) {
                $quality = 100 + strlen( $phrase_lower );
            } elseif ( $word_count == 1 && strlen( $phrase_lower ) >= 6 ) {
                $quality = 50 + strlen( $phrase_lower );
            } elseif ( $word_count <= 6 ) {
                $quality = 30 + strlen( $phrase_lower );
            } else {
                $quality = strlen( $phrase_lower );
            }

            if ( $quality > $best['quality'] ) {
                $best = array( 'text' => $phrase, 'quality' => $quality );
            }
        }

        // Strategy 2: Try slug words in article (Python approach)
        if ( $best['quality'] < 50 ) {
            $slug_words = $this->slug_words_from_url( $page['url'] );
            usort( $slug_words, function( $a, $b ) { return strlen( $b ) - strlen( $a ); } );

            foreach ( $slug_words as $sw ) {
                if ( strlen( $sw ) < 4 ) continue;
                if ( strpos( $plain_lower, $sw ) !== false ) {
                    $quality = 40 + strlen( $sw );
                    if ( $quality > $best['quality'] ) {
                        $best = array( 'text' => $sw, 'quality' => $quality );
                    }
                    break;
                }
            }
        }

        return $best;
    }

    /* ================================================================
     *  LINK INJECTION INTO PARAGRAPH
     * ================================================================ */

    public function inject_link_in_para( $p_tag, $anchor, $url, $title ) {
        if ( empty( $anchor ) || strlen( $anchor ) < 3 || empty( $url ) ) {
            return $p_tag;
        }

        $escaped_anchor = preg_quote( $anchor, '/' );
        $safe_url = esc_url( $url );
        $safe_title = esc_attr( $title );
        $replaced = false;

        $result = preg_replace_callback( '/(<p[^>]*>)(.*?)(<\/p>)/si', function( $m ) use ( $escaped_anchor, $safe_url, $safe_title, &$replaced ) {
            if ( $replaced ) return $m[0];

            $content = $m[2];
            $pattern = '/(?<![<\/a-zA-Z>])(\b' . $escaped_anchor . '\b)(?![^<]*<\/a>)/iu';

            $link_done = false;
            $new_content = @preg_replace_callback( $pattern, function( $lm ) use ( $safe_url, $safe_title, &$link_done ) {
                if ( $link_done ) return $lm[0];
                $link_done = true;
                return '<a href="' . $safe_url . '" title="' . $safe_title . '">' . $lm[1] . '</a>';
            }, $content );

            if ( $new_content !== null && $link_done ) {
                $replaced = true;
                return $m[1] . $new_content . $m[3];
            }
            return $m[0];
        }, $p_tag );

        return ( $result !== null ) ? $result : $p_tag;
    }

    /**
     * Legacy: link first occurrence in any <p> (used by country linker)
     */
    private function link_first_occurrence( $html, $anchor, $url, $title ) {
        if ( empty( $anchor ) || strlen( $anchor ) < 3 || empty( $url ) ) {
            return $html;
        }

        $escaped_anchor = preg_quote( $anchor, '/' );
        $safe_url = esc_url( $url );
        $safe_title = esc_attr( $title );
        $replaced = false;

        $result = preg_replace_callback( '/<p[^>]*>(.*?)<\/p>/si', function( $p_match ) use ( $escaped_anchor, $safe_url, $safe_title, &$replaced ) {
            if ( $replaced ) return $p_match[0];

            $para_content = $p_match[1];
            if ( strpos( $para_content, 'lets-connect' ) !== false ) return $p_match[0];
            if ( strpos( $para_content, 'Damalion experts' ) !== false ) return $p_match[0];

            $pattern = '/(?<![<\/a-zA-Z>])(\b' . $escaped_anchor . '\b)(?![^<]*<\/a>)/iu';

            $para_replaced = false;
            $new_content = @preg_replace_callback( $pattern, function( $match ) use ( $safe_url, $safe_title, &$para_replaced ) {
                if ( $para_replaced ) return $match[0];
                $para_replaced = true;
                return '<a href="' . $safe_url . '" title="' . $safe_title . '">' . $match[1] . '</a>';
            }, $para_content );

            if ( $new_content !== null && $para_replaced ) {
                $replaced = true;
                return str_replace( $para_content, $new_content, $p_match[0] );
            }

            return $p_match[0];
        }, $html );

        return ( $result !== null ) ? $result : $html;
    }

    /* ================================================================
     *  PHASE 1: REPAIR BROKEN LINKS
     * ================================================================ */

    private function repair_broken_links( $html, $full_registry ) {
        $pattern = '/<a\s+([^>]*?)href=["\']https?:\/\/(?:www\.)?damalion\.com\/blog\/?["\']([^>]*?)>(.*?)<\/a>/si';
        $repaired_count = 0;

        $html = preg_replace_callback( $pattern, function( $match ) use ( $full_registry, &$repaired_count ) {
            $attrs_before = $match[1];
            $attrs_after = $match[2];
            $anchor_text = $match[3];
            $full_attrs = $attrs_before . $attrs_after;

            $title = '';
            if ( preg_match( '/title=["\']([^"\']+)["\']/i', $full_attrs, $tm ) ) {
                $title = $tm[1];
            }

            $real_url = $this->find_url_by_title( $title, $full_registry );

            if ( ! $real_url && ! empty( $anchor_text ) ) {
                $clean_anchor = wp_strip_all_tags( $anchor_text );
                $real_url = $this->find_url_by_text( $clean_anchor, $full_registry );
            }

            if ( $real_url ) {
                $repaired_count++;
                error_log( 'DBA Auto-Linker REPAIR: Fixed /blog/ -> ' . $real_url );
                $new_title = esc_attr( $title ? $title : '' );
                $title_attr = ! empty( $new_title ) ? ' title="' . $new_title . '"' : '';
                return '<a href="' . esc_url( $real_url ) . '"' . $title_attr . '>' . $anchor_text . '</a>';
            }

            // CRITICAL FIX: REMOVE the broken link entirely — a link to /blog/ with
            // a fake title like "Doing business in Germany" is WORSE than no link
            // (Google sees it as spammy internal link stuffing).
            // Return just the anchor text (unlinked).
            $clean_text = wp_strip_all_tags( $anchor_text );
            error_log( 'DBA Auto-Linker REPAIR: REMOVED unresolvable /blog/ link — anchor: "' . $clean_text . '", title: "' . $title . '"' );
            return $clean_text;
        }, $html );

        if ( $repaired_count > 0 ) {
            error_log( 'DBA Auto-Linker: Repaired ' . $repaired_count . ' broken /blog/ links' );
        }

        return $html;
    }

    private function find_url_by_title( $title, $full_registry ) {
        if ( empty( $title ) ) return null;

        $title_lower = strtolower( $title );
        $title_words = $this->extract_match_words( $title );

        $best_match = null;
        $best_score = 0;

        foreach ( $full_registry as $page ) {
            if ( strtolower( $page['title'] ) === $title_lower ) {
                return $page['url'];
            }

            $page_words = $this->extract_match_words( $page['slug'] . ' ' . $page['title'] );
            if ( empty( $title_words ) || empty( $page_words ) ) continue;

            $common = count( array_intersect( $title_words, $page_words ) );
            $score = ( $common * $common ) / max( count( $title_words ), count( $page_words ) );

            if ( $score > $best_score && $common >= 2 ) {
                $best_score = $score;
                $best_match = $page['url'];
            }
        }

        return ( $best_score >= 1.5 ) ? $best_match : null;
    }

    private function find_url_by_text( $text, $full_registry ) {
        if ( empty( $text ) || strlen( $text ) < 4 ) return null;
        $text_lower = strtolower( trim( $text ) );

        foreach ( $full_registry as $page ) {
            $keyphrases = isset( $page['keyphrases'] ) ? $page['keyphrases'] : array( $page['title'] );
            foreach ( $keyphrases as $phrase ) {
                $phrase_lower = strtolower( $phrase );
                if ( strlen( $phrase_lower ) < 4 ) continue;
                if ( strpos( $text_lower, $phrase_lower ) !== false || strpos( $phrase_lower, $text_lower ) !== false ) {
                    return $page['url'];
                }
            }
        }
        return null;
    }

    /* ================================================================
     *  UTILITIES
     * ================================================================ */

    private function extract_existing_urls( $html ) {
        $urls = array();
        if ( preg_match_all( '/href=["\']?(https?:\/\/(?:www\.)?damalion\.com[^"\'>\s]*)["\']?/i', $html, $matches ) ) {
            foreach ( $matches[1] as $url ) {
                $urls[] = strtolower( rtrim( $url, '/' ) );
            }
        }
        return array_unique( $urls );
    }

    private function extract_match_words( $text ) {
        $words = preg_split( '/[\s\-_\/]+/', strtolower( trim( $text ) ) );
        $noise = array( 'the','and','for','with','from','this','that','into','about',
            'how','what','why','when','where','a','an','in','on','at','to','of','by',
            'as','is','it','or','be','do','no','set','up','per','via','use','new' );
        $result = array();
        foreach ( $words as $w ) {
            $w = preg_replace( '/[^a-z0-9]/', '', $w );
            if ( strlen( $w ) >= 3 && ! in_array( $w, $noise ) ) {
                $result[] = $w;
            }
        }
        return array_unique( $result );
    }

    /* ================================================================
     *  COUNTRY NAME -> "DOING BUSINESS IN [COUNTRY]" AUTO-LINKING
     * ================================================================ */

    private function get_country_map() {
        return array(
            'Argentina'             => 'https://www.damalion.com/doing-business-in-argentina/',
            'Australia'             => 'https://www.damalion.com/doing-business-in-australia/',
            'Bolivia'               => 'https://www.damalion.com/doing-business-in-bolivia/',
            'Brazil'                => 'https://www.damalion.com/doing-business-in-brazil/',
            'Chile'                 => 'https://www.damalion.com/doing-business-in-chile/',
            'China'                 => 'https://www.damalion.com/doing-business-in-china/',
            'Colombia'              => 'https://www.damalion.com/doing-business-in-colombia/',
            'Costa Rica'            => 'https://www.damalion.com/doing-business-in-costa-rica/',
            'Czech Republic'        => 'https://www.damalion.com/doing-business-in-the-czech-republic/',
            'Denmark'               => 'https://www.damalion.com/doing-business-in-denmark/',
            'Ecuador'               => 'https://www.damalion.com/doing-business-in-ecuador/',
            'El Salvador'           => 'https://www.damalion.com/doing-business-in-el-salvador/',
            'Finland'               => 'https://www.damalion.com/doing-business-in-finland/',
            'France'                => 'https://www.damalion.com/doing-business-in-france/',
            'Germany'               => 'https://www.damalion.com/doing-business-in-germany/',
            'Guatemala'             => 'https://www.damalion.com/doing-business-in-guatemala/',
            'Israel'                => 'https://www.damalion.com/doing-business-in-israel/',
            'Italy'                 => 'https://www.damalion.com/doing-business-in-italy/',
            'Japan'                 => 'https://www.damalion.com/doing-business-in-japan/',
            'Luxembourg'            => 'https://www.damalion.com/doing-business-in-luxembourg/',
            'Mexico'                => 'https://www.damalion.com/doing-business-in-mexico/',
            'Morocco'               => 'https://www.damalion.com/doing-business-in-morocco/',
            'Norway'                => 'https://www.damalion.com/doing-business-in-norway/',
            'Paraguay'              => 'https://www.damalion.com/doing-business-in-paraguay/',
            'Peru'                  => 'https://www.damalion.com/doing-business-in-peru/',
            'Portugal'              => 'https://www.damalion.com/doing-business-in-portugal/',
            'Puerto Rico'           => 'https://www.damalion.com/doing-business-in-puerto-rico/',
            'Qatar'                 => 'https://www.damalion.com/doing-business-in-qatar/',
            'Russia'                => 'https://www.damalion.com/doing-business-in-russia/',
            'Rwanda'                => 'https://www.damalion.com/doing-business-in-rwanda/',
            'South Korea'           => 'https://www.damalion.com/doing-business-in-south-korea/',
            'Spain'                 => 'https://www.damalion.com/doing-business-in-spain/',
            'Sweden'                => 'https://www.damalion.com/doing-business-in-sweden/',
            'Switzerland'           => 'https://www.damalion.com/doing-business-in-switzerland/',
            'Turkey'                => 'https://www.damalion.com/doing-business-in-turkey/',
            'United Arab Emirates'  => 'https://www.damalion.com/doing-business-in-united-arab-emirates-uae/',
            'UAE'                   => 'https://www.damalion.com/doing-business-in-united-arab-emirates-uae/',
            'Ukraine'               => 'https://www.damalion.com/doing-business-in-ukraine/',
            'Uruguay'               => 'https://www.damalion.com/doing-business-in-uruguay/',
            'USA'                   => 'https://www.damalion.com/doing-business-in-usa/',
            'United States'         => 'https://www.damalion.com/doing-business-in-usa/',
        );
    }

    public function link_country_names( $html ) {
        if ( empty( $html ) || strlen( $html ) < 200 ) {
            return $html;
        }

        $country_map = $this->get_country_map();

        uksort( $country_map, function( $a, $b ) {
            return strlen( $b ) - strlen( $a );
        } );

        $existing_urls = $this->extract_existing_urls( $html );
        $existing_country_urls = array();
        foreach ( $country_map as $url ) {
            $url_clean = strtolower( rtrim( $url, '/' ) );
            if ( in_array( $url_clean, $existing_urls ) ) {
                $existing_country_urls[] = $url_clean;
            }
        }

        $linked_count = 0;
        $linked_countries = array();

        foreach ( $country_map as $country_name => $country_url ) {
            $url_clean = strtolower( rtrim( $country_url, '/' ) );

            if ( in_array( $url_clean, $existing_country_urls ) ) continue;
            if ( in_array( $url_clean, $linked_countries ) ) continue;

            $title_attr = 'Doing business in ' . $country_name;
            $new_html = $this->link_first_occurrence( $html, $country_name, $country_url, $title_attr );

            if ( $new_html !== $html ) {
                $html = $new_html;
                $linked_count++;
                $linked_countries[] = $url_clean;
                error_log( 'DBA Country-Linker: Linked "' . $country_name . '" -> ' . $country_url );
            }
        }

        if ( $linked_count > 0 ) {
            error_log( 'DBA Country-Linker: Linked ' . $linked_count . ' country names' );
        }

        return $html;
    }
}
