<?php
/**
 * DBA_LuxStrat_Intl_Anti_Orphan — Cross-linking + Luxembourg authority links
 *
 * LANGUAGE-AWARE + WPML-SAFE: cross-links ONLY within the same language.
 * Meta prefix via DBA_LuxStrat_Intl_Dedupe::meta_prefix($lang).
 *
 * 1. Injects Luxembourg authority outbound links (CSSF, Guichet.lu, RCS, ACD, Legilux)
 * 2. Appends "Related" block to new post → 2–3 existing same-lang posts
 * 3. Injects backlinks FROM related same-lang posts → new post
 * 4. 30-min verification + weekly audit across all loaded languages
 *
 * Drop into /luxstrat-intl/ folder.
 * @since 2.17.0
 */
if ( ! defined( 'ABSPATH' ) ) exit;

class DBA_LuxStrat_Intl_Anti_Orphan {

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

    const RELATED_CLASS   = 'dba-lsi-related';
    const AUTH_LINK_CLASS = 'dba-lsi-auth-link';
    const VERIFY_HOOK     = 'dba_lsi_verify_link';
    const AUDIT_HOOK      = 'dba_lsi_weekly_orphan_audit';

    /* ══════════════════════════════════════════════════════════════════
     *  LUXEMBOURG AUTHORITY URLs — multilingual keywords
     * ══════════════════════════════════════════════════════════════════ */
    private static $authority_urls = array(
        'cssf' => array(
            'url'   => 'https://www.cssf.lu',
            'label' => 'CSSF (Commission de Surveillance du Secteur Financier)',
            'short' => 'CSSF',
            'keywords' => array(
                'CSSF', 'Commission de Surveillance', 'financial regulator', 'Luxembourg regulator',
                'régulateur financier', 'autorité de surveillance', 'supervisione finanziaria',
            ),
        ),
        'guichet' => array(
            'url'   => 'https://guichet.public.lu',
            'label' => 'Guichet.lu — Luxembourg Business Portal',
            'short' => 'Guichet.lu',
            'keywords' => array(
                'Guichet', 'business portal', 'portail entreprises', 'portale imprese',
                'création d\'entreprise', 'costituzione società',
            ),
        ),
        'rcs' => array(
            'url'   => 'https://www.lbr.lu',
            'label' => 'Luxembourg Business Registers (RCS)',
            'short' => 'RCS',
            'keywords' => array(
                'RCS', 'Business Register', 'Registre de Commerce', 'RCSL',
                'registro delle imprese', 'registre du commerce',
            ),
        ),
        'tax' => array(
            'url'   => 'https://impotsdirects.public.lu',
            'label' => 'Luxembourg Tax Administration (ACD)',
            'short' => 'ACD',
            'keywords' => array(
                'Administration des Contributions Directes', 'Luxembourg tax', 'ACD',
                'subscription tax', 'impôt sur le revenu', 'taxe d\'abonnement',
                'imposta societaria', 'tassa di sottoscrizione',
            ),
        ),
        'legilux' => array(
            'url'   => 'https://legilux.public.lu',
            'label' => 'Legilux — Official Luxembourg Legislation',
            'short' => 'Legilux',
            'keywords' => array(
                'Legilux', 'legislation', 'Law of 10 August 1915', 'Law of 23 July 2016',
                'loi du 10 août 1915', 'loi du 23 juillet 2016',
                'legge del 10 agosto 1915', 'quadro giuridico', 'cadre juridique',
            ),
        ),
    );

    /* ── Localised headings ── */
    private static $related_headings = array(
        'en' => 'Related Luxembourg Structuring Insights',
        'fr' => 'Articles connexes sur la structuration luxembourgeoise',
        'it' => 'Approfondimenti correlati sulla strutturazione lussemburghese',
        'de' => 'Verwandte Einblicke in die Luxemburger Strukturierung',
        'es' => 'Perspectivas relacionadas sobre la estructuración en Luxemburgo',
    );

    private function __construct() {
        add_action( self::VERIFY_HOOK, array( $this, 'verify_link' ), 10, 2 );
        add_action( self::AUDIT_HOOK,  array( $this, 'run_weekly_audit' ) );
        if ( ! wp_next_scheduled( self::AUDIT_HOOK ) ) {
            wp_schedule_event( time() + WEEK_IN_SECONDS, 'weekly', self::AUDIT_HOOK );
        }
    }

    private static function heading( $lang ) {
        return self::$related_headings[ $lang ] ?? self::$related_headings['en'];
    }

    /* ══════════════════════════════════════════════════════════════════
     *  INJECT AUTHORITY LINKS into article content
     * ══════════════════════════════════════════════════════════════════ */
    public static function inject_authority_links( $content ) {
        $injected  = 0;
        $max_links = 2;

        foreach ( self::$authority_urls as $key => $auth ) {
            if ( $injected >= $max_links ) break;
            if ( strpos( $content, $auth['url'] ) !== false ) continue;

            foreach ( $auth['keywords'] as $kw ) {
                if ( $injected >= $max_links ) break;
                $kw_esc  = preg_quote( $kw, '/' );
                $pattern = '/(<p[^>]*>)((?:(?!<\/p>).)*?)(\b' . $kw_esc . '\b)((?:(?!<\/p>).)*?)(<\/p>)/siu';

                $content = preg_replace_callback(
                    $pattern,
                    function( $m ) use ( $auth, &$injected, $max_links ) {
                        if ( $injected >= $max_links ) return $m[0];
                        if ( preg_match( '/<a\s/i', $m[2] . $m[3] ) ) return $m[0];
                        $injected++;
                        return $m[1] . $m[2]
                            . '<a href="' . esc_url( $auth['url'] ) . '" target="_blank" rel="noopener noreferrer" class="' . self::AUTH_LINK_CLASS . '" title="' . esc_attr( $auth['label'] ) . '">' . $m[3] . '</a>'
                            . $m[4] . $m[5];
                    },
                    $content, 1
                );
                if ( $injected > 0 && strpos( $content, $auth['url'] ) !== false ) break;
            }
        }
        return $content;
    }

    /* ══════════════════════════════════════════════════════════════════
     *  APPEND RELATED BLOCK — same language ONLY (WPML safe)
     * ══════════════════════════════════════════════════════════════════ */
    public static function append_related_block( $lang, $post_id, $theme_slug ) {
        global $wpdb;
        $prefix = DBA_LuxStrat_Intl_Dedupe::meta_prefix( $lang );

        // Only match posts from SAME language
        $related = $wpdb->get_results( $wpdb->prepare(
            "SELECT p.ID, p.post_title, pt.meta_value AS theme_slug
             FROM {$wpdb->posts} p
             INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key=%s
             LEFT JOIN {$wpdb->postmeta} pt ON p.ID=pt.post_id AND pt.meta_key=%s
             WHERE p.post_status='publish' AND p.ID!=%d
             ORDER BY
               CASE WHEN pt.meta_value=%s THEN 0 ELSE 1 END,
               p.post_date DESC
             LIMIT 3",
            $prefix . 'auto_created', $prefix . 'theme', $post_id, $theme_slug
        ), ARRAY_A );

        if ( empty( $related ) ) return false;

        $heading = self::heading( $lang );
        $block   = "\n\n<!-- LuxStrat-Intl Anti-Orphan [{$lang}] -->\n"
            . '<div class="' . self::RELATED_CLASS . '" style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;padding:18px 22px;margin:28px 0;">'
            . "\n<h3 style=\"margin-top:0;color:#1a365d;\">{$heading}</h3>\n<ul>\n";

        foreach ( $related as $r ) {
            $url = get_permalink( $r['ID'] );
            if ( ! $url ) continue;
            $block .= '<li><a href="' . esc_url( $url ) . '">' . esc_html( $r['post_title'] ) . '</a></li>' . "\n";
        }
        $block .= "</ul>\n</div>\n";

        $content  = get_post_field( 'post_content', $post_id );
        $content .= $block;
        $wpdb->update( $wpdb->posts, array( 'post_content' => $content ), array( 'ID' => $post_id ) );
        clean_post_cache( $post_id );
        return count( $related );
    }

    /* ══════════════════════════════════════════════════════════════════
     *  INJECT BACKLINKS — same language ONLY
     * ══════════════════════════════════════════════════════════════════ */
    public static function inject_backlinks( $lang, $new_post_id ) {
        global $wpdb;
        $prefix = DBA_LuxStrat_Intl_Dedupe::meta_prefix( $lang );

        $targets = $wpdb->get_results( $wpdb->prepare(
            "SELECT p.ID, p.post_content FROM {$wpdb->posts} p
             INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key=%s
             WHERE p.post_status='publish' AND p.ID!=%d
             ORDER BY p.post_date DESC LIMIT 3",
            $prefix . 'auto_created', $new_post_id
        ), ARRAY_A );

        $new_url   = get_permalink( $new_post_id );
        $new_title = get_the_title( $new_post_id );
        if ( ! $new_url ) return 0;

        $count = 0;
        foreach ( $targets as $t ) {
            if ( strpos( $t['post_content'], $new_url ) !== false ) continue;
            $li = '<li><a href="' . esc_url( $new_url ) . '">' . esc_html( $new_title ) . '</a></li>';

            if ( strpos( $t['post_content'], self::RELATED_CLASS ) !== false ) {
                $updated = str_replace( '</ul>', $li . "\n</ul>", $t['post_content'] );
            } else {
                $heading = self::heading( $lang );
                $updated = $t['post_content']
                    . "\n<!-- LuxStrat-Intl Anti-Orphan Backlink [{$lang}] -->\n"
                    . '<div class="' . self::RELATED_CLASS . '" style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;padding:18px 22px;margin:28px 0;">'
                    . "\n<h3 style=\"margin-top:0;color:#1a365d;\">{$heading}</h3>\n<ul>\n"
                    . $li . "\n</ul>\n</div>\n";
            }
            $wpdb->update( $wpdb->posts, array( 'post_content' => $updated ), array( 'ID' => $t['ID'] ) );
            clean_post_cache( $t['ID'] );
            $count++;
        }
        return $count;
    }

    /* ══════════════════════════════════════════════════════════════════
     *  FULL PIPELINE — call from generator after post creation
     * ══════════════════════════════════════════════════════════════════ */
    public static function on_post_created( $lang, $post_id, $theme_slug ) {
        // 1. Authority links
        $content = get_post_field( 'post_content', $post_id );
        $updated = self::inject_authority_links( $content );
        if ( $updated !== $content ) {
            global $wpdb;
            $wpdb->update( $wpdb->posts, array( 'post_content' => $updated ), array( 'ID' => $post_id ) );
            clean_post_cache( $post_id );
        }

        // 2. Related block (same language only)
        $related = self::append_related_block( $lang, $post_id, $theme_slug );

        // 3. Backlinks (same language only)
        $backlinks = self::inject_backlinks( $lang, $post_id );

        // 4. Schedule 30-min verification
        wp_schedule_single_event( time() + 1800, self::VERIFY_HOOK, array( $post_id, $lang ) );

        return array(
            'auth_links' => ( $updated !== $content ) ? 1 : 0,
            'related'    => $related ?: 0,
            'backlinks'  => $backlinks,
        );
    }

    /* ══════════════════════════════════════════════════════════════════
     *  VERIFY — 30 min after creation
     * ══════════════════════════════════════════════════════════════════ */
    public function verify_link( $post_id, $lang = '' ) {
        if ( get_post_status( $post_id ) !== 'publish' ) return;

        // Auto-detect language from meta if not provided
        if ( ! $lang && class_exists( 'DBA_LuxStrat_Intl_Loader' ) ) {
            foreach ( array_keys( DBA_LuxStrat_Intl_Loader::get_languages() ) as $try ) {
                $pfx = DBA_LuxStrat_Intl_Dedupe::meta_prefix( $try );
                if ( get_post_meta( $post_id, $pfx . 'auto_created', true ) ) { $lang = $try; break; }
            }
        }
        if ( ! $lang ) return;

        $content = get_post_field( 'post_content', $post_id );

        if ( strpos( $content, self::RELATED_CLASS ) === false ) {
            $prefix = DBA_LuxStrat_Intl_Dedupe::meta_prefix( $lang );
            $theme  = get_post_meta( $post_id, $prefix . 'theme', true );
            self::append_related_block( $lang, $post_id, $theme ?: '' );
            error_log( "LuxStrat-Intl Anti-Orphan [{$lang}]: verify fixed orphan #{$post_id}" );
        }

        if ( strpos( $content, self::AUTH_LINK_CLASS ) === false ) {
            $content = get_post_field( 'post_content', $post_id ); // re-read after related block
            $updated = self::inject_authority_links( $content );
            if ( $updated !== $content ) {
                global $wpdb;
                $wpdb->update( $wpdb->posts, array( 'post_content' => $updated ), array( 'ID' => $post_id ) );
                clean_post_cache( $post_id );
            }
        }
    }

    /* ══════════════════════════════════════════════════════════════════
     *  AUDIT — per language
     * ══════════════════════════════════════════════════════════════════ */
    public static function audit_language( $lang ) {
        global $wpdb;
        $prefix = DBA_LuxStrat_Intl_Dedupe::meta_prefix( $lang );

        $ids = $wpdb->get_col( $wpdb->prepare(
            "SELECT p.ID FROM {$wpdb->posts} p
             INNER JOIN {$wpdb->postmeta} pm ON p.ID=pm.post_id AND pm.meta_key=%s
             WHERE p.post_status='publish' ORDER BY p.post_date DESC",
            $prefix . 'auto_created'
        ) );

        $total = count( $ids ); $orphaned = 0; $fixed = 0;

        foreach ( $ids as $pid ) {
            $content = get_post_field( 'post_content', $pid );

            if ( strpos( $content, self::RELATED_CLASS ) === false ) {
                $orphaned++;
                $theme = get_post_meta( $pid, $prefix . 'theme', true );
                if ( self::append_related_block( $lang, $pid, $theme ?: '' ) ) $fixed++;
            }

            if ( strpos( $content, self::AUTH_LINK_CLASS ) === false ) {
                $content = get_post_field( 'post_content', $pid );
                $updated = self::inject_authority_links( $content );
                if ( $updated !== $content ) {
                    $wpdb->update( $wpdb->posts, array( 'post_content' => $updated ), array( 'ID' => $pid ) );
                    clean_post_cache( $pid );
                }
            }
        }
        return array( 'total' => $total, 'orphaned' => $orphaned, 'fixed' => $fixed );
    }

    public function run_weekly_audit() {
        if ( ! class_exists( 'DBA_LuxStrat_Intl_Loader' ) ) return;
        $languages = DBA_LuxStrat_Intl_Loader::get_languages();
        foreach ( array_keys( $languages ) as $lang ) {
            $result = self::audit_language( $lang );
            error_log( "LuxStrat-Intl Anti-Orphan [{$lang}]: audit — {$result['fixed']}/{$result['orphaned']} orphans fixed ({$result['total']} total)" );
        }
    }

    /* ══════════════════════════════════════════════════════════════════
     *  ADMIN HELPERS — per language
     * ══════════════════════════════════════════════════════════════════ */
    public static function get_orphan_stats( $lang ) {
        global $wpdb;
        $prefix = DBA_LuxStrat_Intl_Dedupe::meta_prefix( $lang );

        $all = $wpdb->get_col( $wpdb->prepare(
            "SELECT pm.post_id FROM {$wpdb->postmeta} pm
             INNER JOIN {$wpdb->posts} p ON pm.post_id=p.ID
             WHERE pm.meta_key=%s AND p.post_status='publish'
             ORDER BY p.post_date DESC",
            $prefix . 'auto_created'
        ) );

        $total = count( $all ); $linked = 0; $auth_linked = 0; $orphans = array();
        foreach ( $all as $pid ) {
            $c = get_post_field( 'post_content', $pid );
            if ( strpos( $c, self::RELATED_CLASS ) !== false ) $linked++;
            if ( strpos( $c, self::AUTH_LINK_CLASS ) !== false ) $auth_linked++;
            if ( strpos( $c, self::RELATED_CLASS ) === false && count( $orphans ) < 10 ) {
                $orphans[] = array( 'id' => $pid, 'title' => get_the_title( $pid ) );
            }
        }

        return array(
            'total'        => $total,
            'linked'       => $linked,
            'auth_linked'  => $auth_linked,
            'orphan_count' => $total - $linked,
            'orphans'      => $orphans,
        );
    }

    public static function get_all_authority_urls() {
        return self::$authority_urls;
    }
}
