<?php
/**
 * DBA GeoBot Anti-Orphan Protection
 *
 * Ensures every GeoBot city article is linked FROM the country hub page
 * and has cross-links to/from related city articles in the same country.
 *
 * Features:
 *   - Auto-append new city posts to the hub page city list
 *   - Inject "Related Cities" section into existing posts
 *   - Schedule verification cron to catch missed links
 *   - Weekly audit to find and fix orphaned posts
 *   - Country-scoped: each country hub managed independently
 *
 * ═══════════════════════════════════════════════════════════════════════
 *  ZERO CONFLICT: Completely separate from Startup Hub Anti-Orphan
 *  and core DBA_Linker. Uses GeoBot Registry for all config.
 * ═══════════════════════════════════════════════════════════════════════
 *
 * @since 2.17.0
 */

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

class DBA_GeoBot_Anti_Orphan {

    private static $instance = null;

    /** Marker comment used in hub pages to locate the city list. */
    const HUB_LIST_MARKER = '<!-- GEOBOT_CITY_LIST -->';

    /** Cron hook for single-post verification. */
    const VERIFY_HOOK = 'dba_geobot_verify_link';

    /** Cron hook for weekly audit. */
    const AUDIT_HOOK = 'dba_geobot_weekly_orphan_audit';

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

    private function __construct() {
        add_action( self::VERIFY_HOOK, array( $this, 'verify_single_post' ), 10, 2 );
        add_action( self::AUDIT_HOOK,  array( $this, 'run_all_country_audits' ) );

        // Schedule weekly audit if not already scheduled
        if ( ! wp_next_scheduled( self::AUDIT_HOOK ) ) {
            wp_schedule_event( time() + DAY_IN_SECONDS, 'weekly', self::AUDIT_HOOK );
        }
    }

    /* =================================================================
     *  LINK FROM HUB PAGE
     *
     *  Appends the new city article to the country hub page's list.
     *  Hub pages use <!-- GEOBOT_CITY_LIST --> as the insertion marker.
     * ================================================================= */

    /**
     * Link a new post from the country hub page.
     *
     * @param string $country_key  Country key (e.g. 'france', 'italy').
     * @param int    $post_id      New post ID.
     * @param string $commune      City/commune name.
     * @param string $region       Region name (for display).
     * @return bool                True if linked, false if skipped/failed.
     */
    public function link_from_hub_page( string $country_key, int $post_id, string $commune, string $region = '' ) {

        $hub_id = intval( get_option( 'dba_geo_' . $country_key . '_hub_page_id', 0 ) );

        if ( ! $hub_id || ! get_post_status( $hub_id ) || get_post_status( $hub_id ) === 'trash' ) {
            error_log( "DBA GeoBot Anti-Orphan [{$country_key}]: No hub page found. Skipping hub link for #{$post_id}" );
            return false;
        }

        $hub_content = get_post_field( 'post_content', $hub_id );
        $permalink   = get_permalink( $post_id );
        $title       = get_the_title( $post_id );

        // Already linked?
        if ( strpos( $hub_content, $permalink ) !== false ) {
            error_log( "DBA GeoBot Anti-Orphan [{$country_key}]: Post #{$post_id} ({$commune}) already linked from hub." );
            return true;
        }

        // Build the link HTML — city name with region context
        $region_suffix = ! empty( $region ) ? ' — <em>' . esc_html( $region ) . '</em>' : '';
        $link_html     = '<li><a href="' . esc_url( $permalink ) . '">' . esc_html( $title ) . '</a>'
            . $region_suffix . '</li>';

        // Strategy 1: Insert at the GEOBOT_CITY_LIST marker
        if ( strpos( $hub_content, self::HUB_LIST_MARKER ) !== false ) {
            $marker_pos = strpos( $hub_content, self::HUB_LIST_MARKER );
            $after      = substr( $hub_content, $marker_pos + strlen( self::HUB_LIST_MARKER ) );

            // Look for existing <ul> within 50 chars after marker
            $ul_open_pos = strpos( $after, '<ul>' );

            if ( $ul_open_pos === false || $ul_open_pos > 50 ) {
                // No <ul> right after marker — create one
                $new_content = substr( $hub_content, 0, $marker_pos + strlen( self::HUB_LIST_MARKER ) )
                    . "\n<ul>\n" . $link_html . "\n</ul>"
                    . $after;
            } else {
                // Insert into existing <ul> (before closing </ul>)
                $ul_close_pos = strpos( $after, '</ul>' );
                if ( $ul_close_pos !== false ) {
                    $abs_pos = $marker_pos + strlen( self::HUB_LIST_MARKER ) + $ul_close_pos;
                    $new_content = substr( $hub_content, 0, $abs_pos )
                        . $link_html . "\n"
                        . substr( $hub_content, $abs_pos );
                } else {
                    // Fallback: append list at end
                    $new_content = $hub_content . "\n<ul>\n" . $link_html . "\n</ul>";
                }
            }
        }
        // Strategy 2: No marker — find the CTA and insert before it
        else {
            $cta_pos = stripos( $hub_content, 'GeoBot CTA' );
            if ( ! $cta_pos ) $cta_pos = stripos( $hub_content, 'damalion-cta' );

            if ( $cta_pos !== false ) {
                // Find the start of the CTA div/comment
                $div_start = strrpos( substr( $hub_content, 0, $cta_pos ), '<' );
                if ( $div_start !== false ) {
                    $new_content = substr( $hub_content, 0, $div_start )
                        . "\n" . self::HUB_LIST_MARKER . "\n<ul>\n" . $link_html . "\n</ul>\n\n"
                        . substr( $hub_content, $div_start );
                } else {
                    $new_content = $hub_content . "\n\n" . self::HUB_LIST_MARKER . "\n<ul>\n" . $link_html . "\n</ul>";
                }
            } else {
                // Last resort: append at end
                $new_content = $hub_content . "\n\n" . self::HUB_LIST_MARKER . "\n<ul>\n" . $link_html . "\n</ul>";
            }
        }

        wp_update_post( array(
            'ID'           => $hub_id,
            'post_content' => $new_content,
        ) );

        error_log( "DBA GeoBot Anti-Orphan [{$country_key}]: Linked post #{$post_id} ({$commune}) from hub #{$hub_id}" );
        return true;
    }

    /* =================================================================
     *  CROSS-LINK FROM RELATED CITY POSTS
     *
     *  Injects a "Related Cities" / "Città correlate" section
     *  into up to 3 existing posts in the same region or country.
     * ================================================================= */

    /**
     * Inject backlinks from related city posts to the new post.
     *
     * Finds related posts by:
     *   1. Same region (highest relevance)
     *   2. Same country (fallback)
     *
     * @param string $country_key  Country key.
     * @param int    $post_id      New post ID.
     * @param string $commune      City name.
     * @param string $region       Region name.
     */
    public function inject_backlinks_from_related( string $country_key, int $post_id, string $commune, string $region = '' ) {

        $config = DBA_GeoBot_Registry::get_country( $country_key );
        if ( ! $config ) return;

        $meta_prefix = $config['meta_prefix'];

        // Build meta query: same country, optionally same region
        $meta_query = array(
            'relation' => 'AND',
            array( 'key' => $meta_prefix . 'auto_created', 'compare' => 'EXISTS' ),
            array( 'key' => $meta_prefix . 'country', 'value' => $country_key ),
        );

        // Find related posts: prefer same region, fall back to same country
        $related = get_posts( array(
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => 8,
            'fields'         => 'ids',
            'exclude'        => array( $post_id ),
            'meta_query'     => $meta_query,
            'orderby'        => 'date',
            'order'          => 'DESC',
        ) );

        if ( empty( $related ) ) {
            error_log( "DBA GeoBot Anti-Orphan [{$country_key}]: No related posts found for cross-linking #{$post_id} ({$commune})" );
            return;
        }

        // Prioritize same-region posts
        $same_region = array();
        $other       = array();

        foreach ( $related as $rid ) {
            $r_region = get_post_meta( $rid, $meta_prefix . 'region', true );
            if ( ! empty( $region ) && $r_region === $region ) {
                $same_region[] = $rid;
            } else {
                $other[] = $rid;
            }
        }

        // Take up to 3: same-region first, then others
        $targets = array_merge( $same_region, $other );
        $targets = array_slice( $targets, 0, 3 );

        $new_permalink = get_permalink( $post_id );
        $new_title     = get_the_title( $post_id );
        $linked_count  = 0;

        // Language-specific heading for the related section
        $related_headings = array(
            'fr' => 'Villes liées',
            'it' => 'Città correlate',
            'es' => 'Ciudades relacionadas',
            'pt' => 'Cidades relacionadas',
            'en' => 'Related Cities',
        );
        $related_heading = $related_headings[ $config['language'] ] ?? 'Related Cities';

        foreach ( $targets as $related_id ) {
            $rel_content = get_post_field( 'post_content', $related_id );

            // Skip if already linked
            if ( strpos( $rel_content, $new_permalink ) !== false ) continue;

            // Build the related section block
            $section = "\n\n" . '<div class="geobot-related-cities" style="background:#f9fafb;border:1px solid #e5e7eb;border-radius:6px;padding:16px 20px;margin:24px 0;">'
                . '<h3 style="margin:0 0 8px;font-size:1em;">' . esc_html( $related_heading ) . '</h3>'
                . '<p style="margin:0;"><a href="' . esc_url( $new_permalink ) . '">' . esc_html( $new_title ) . '</a></p>'
                . '</div>';

            // Inject before CTA if present, otherwise append
            $cta_pos = stripos( $rel_content, 'GeoBot CTA' );
            if ( ! $cta_pos ) $cta_pos = stripos( $rel_content, 'damalion-cta' );

            if ( $cta_pos !== false ) {
                $tag_start = strrpos( substr( $rel_content, 0, $cta_pos ), '<' );
                if ( $tag_start !== false ) {
                    $updated = substr( $rel_content, 0, $tag_start ) . $section . "\n" . substr( $rel_content, $tag_start );
                } else {
                    $updated = $rel_content . $section;
                }
            } else {
                $updated = $rel_content . $section;
            }

            wp_update_post( array(
                'ID'           => $related_id,
                'post_content' => $updated,
            ) );

            $linked_count++;
        }

        error_log( "DBA GeoBot Anti-Orphan [{$country_key}]: Injected backlinks in {$linked_count} related posts for #{$post_id} ({$commune})" );
    }

    /* =================================================================
     *  ALSO LINK NEW POST BACK TO RELATED CITIES
     *
     *  When a new post is created, append a "Related Cities" block
     *  that links to 2-3 already-published posts in the same region.
     *  This ensures the NEW post also has outbound internal links
     *  (not just inbound from others).
     * ================================================================= */

    /**
     * Append a related cities block TO the new post.
     *
     * @param string $country_key
     * @param int    $post_id      New post ID.
     * @param string $region       Region name.
     * @return bool
     */
    public function append_related_to_new_post( string $country_key, int $post_id, string $region = '' ) {

        $config = DBA_GeoBot_Registry::get_country( $country_key );
        if ( ! $config ) return false;

        $meta_prefix = $config['meta_prefix'];

        // Find published posts in same country (prefer same region)
        $related = get_posts( array(
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => 6,
            'fields'         => 'ids',
            'exclude'        => array( $post_id ),
            'meta_query'     => array(
                array( 'key' => $meta_prefix . 'auto_created', 'compare' => 'EXISTS' ),
                array( 'key' => $meta_prefix . 'country', 'value' => $country_key ),
            ),
            'orderby' => 'rand',
        ) );

        if ( empty( $related ) ) return false;

        // Prioritize same-region
        $same_region = array();
        $other       = array();
        foreach ( $related as $rid ) {
            $r_region = get_post_meta( $rid, $meta_prefix . 'region', true );
            if ( ! empty( $region ) && $r_region === $region ) {
                $same_region[] = $rid;
            } else {
                $other[] = $rid;
            }
        }

        $picks = array_slice( array_merge( $same_region, $other ), 0, 3 );
        if ( empty( $picks ) ) return false;

        $related_headings = array(
            'fr' => 'Découvrez aussi',
            'it' => 'Scopri anche',
            'es' => 'Descubre también',
            'pt' => 'Descubra também',
            'en' => 'Explore More Cities',
        );
        $heading = $related_headings[ $config['language'] ] ?? 'Explore More Cities';

        $links_html = '';
        foreach ( $picks as $rid ) {
            $links_html .= '<li><a href="' . esc_url( get_permalink( $rid ) ) . '">'
                . esc_html( get_the_title( $rid ) ) . '</a></li>';
        }

        $block = "\n\n" . '<div class="geobot-related-cities" style="background:#f9fafb;border:1px solid #e5e7eb;border-radius:6px;padding:16px 20px;margin:24px 0;">'
            . '<h3 style="margin:0 0 10px;font-size:1em;">' . esc_html( $heading ) . '</h3>'
            . '<ul style="margin:0;padding-left:20px;">' . $links_html . '</ul>'
            . '</div>';

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

        // Insert before CTA if present
        $cta_pos = stripos( $content, 'GeoBot CTA' );
        if ( ! $cta_pos ) $cta_pos = stripos( $content, 'damalion-cta' );

        if ( $cta_pos !== false ) {
            $tag_start = strrpos( substr( $content, 0, $cta_pos ), '<' );
            if ( $tag_start !== false ) {
                $updated = substr( $content, 0, $tag_start ) . $block . "\n" . substr( $content, $tag_start );
            } else {
                $updated = $content . $block;
            }
        } else {
            $updated = $content . $block;
        }

        wp_update_post( array(
            'ID'           => $post_id,
            'post_content' => $updated,
        ) );

        error_log( "DBA GeoBot Anti-Orphan [{$country_key}]: Appended " . count( $picks ) . " related city links to new post #{$post_id}" );
        return true;
    }

    /* =================================================================
     *  FULL ANTI-ORPHAN PIPELINE — Call this after post creation
     * ================================================================= */

    /**
     * Run the complete anti-orphan pipeline for a newly created post.
     *
     * @param string $country_key
     * @param int    $post_id
     * @param string $commune
     * @param string $region
     */
    public function on_post_created( string $country_key, int $post_id, string $commune, string $region = '' ) {

        // 1. Link from hub page
        $this->link_from_hub_page( $country_key, $post_id, $commune, $region );

        // 2. Inject backlinks INTO related posts (they now point to new post)
        $this->inject_backlinks_from_related( $country_key, $post_id, $commune, $region );

        // 3. Append related cities block TO the new post (outbound links)
        $this->append_related_to_new_post( $country_key, $post_id, $region );

        // 4. Schedule verification (30 min later)
        $this->schedule_verification( $country_key, $post_id );
    }

    /* =================================================================
     *  VERIFICATION SCHEDULING
     * ================================================================= */

    /**
     * Schedule a one-time verification for a post (30 min after publish).
     *
     * @param string $country_key
     * @param int    $post_id
     */
    public function schedule_verification( string $country_key, int $post_id ) {
        $timestamp = time() + ( 30 * MINUTE_IN_SECONDS );
        wp_schedule_single_event( $timestamp, self::VERIFY_HOOK, array( $country_key, $post_id ) );
    }

    /**
     * Verify that a published post is linked from the hub page.
     * If not, re-run the hub link process.
     *
     * @param string $country_key
     * @param int    $post_id
     */
    public function verify_single_post( $country_key, $post_id ) {

        $hub_id = intval( get_option( 'dba_geo_' . $country_key . '_hub_page_id', 0 ) );
        if ( ! $hub_id ) return;

        $hub_content = get_post_field( 'post_content', $hub_id );
        $permalink   = get_permalink( $post_id );

        if ( $permalink && strpos( $hub_content, $permalink ) === false ) {
            $config  = DBA_GeoBot_Registry::get_country( $country_key );
            $commune = $config ? get_post_meta( $post_id, $config['meta_prefix'] . 'commune', true ) : '';
            $region  = $config ? get_post_meta( $post_id, $config['meta_prefix'] . 'region', true ) : '';

            $this->link_from_hub_page( $country_key, $post_id, $commune ?: 'Unknown', $region );
            error_log( "DBA GeoBot Anti-Orphan [{$country_key}]: Verification fixed orphan #{$post_id}" );
        }
    }

    /* =================================================================
     *  WEEKLY AUDIT — Scan ALL countries for orphaned posts
     * ================================================================= */

    /**
     * Run audit for all registered countries (called by cron).
     */
    public function run_all_country_audits() {
        $total_results = array();

        foreach ( DBA_GeoBot_Registry::get_countries() as $key => $config ) {
            $result = $this->audit_country( $key );
            $total_results[ $key ] = $result;
        }

        error_log( 'DBA GeoBot Anti-Orphan: Weekly audit complete — ' . wp_json_encode( $total_results ) );
        return $total_results;
    }

    /**
     * Scan all GeoBot posts for a single country and fix orphans.
     *
     * @param string $country_key
     * @return array { 'total' => int, 'orphaned' => int, 'fixed' => int }
     */
    public function audit_country( string $country_key ) {

        $config = DBA_GeoBot_Registry::get_country( $country_key );
        $result = array( 'total' => 0, 'orphaned' => 0, 'fixed' => 0 );

        if ( ! $config ) return $result;

        $hub_id = intval( get_option( 'dba_geo_' . $country_key . '_hub_page_id', 0 ) );

        if ( ! $hub_id || ! get_post_status( $hub_id ) || get_post_status( $hub_id ) === 'trash' ) {
            error_log( "DBA GeoBot Anti-Orphan Audit [{$country_key}]: No hub page — aborting." );
            return $result;
        }

        $hub_content = get_post_field( 'post_content', $hub_id );
        $meta_prefix = $config['meta_prefix'];

        $all_posts = get_posts( array(
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => -1,
            'fields'         => 'ids',
            'meta_query'     => array(
                array( 'key' => $meta_prefix . 'auto_created', 'compare' => 'EXISTS' ),
                array( 'key' => $meta_prefix . 'country', 'value' => $country_key ),
            ),
        ) );

        $result['total'] = count( $all_posts );

        foreach ( $all_posts as $pid ) {
            if ( $pid == $hub_id ) continue;

            $permalink = get_permalink( $pid );
            if ( $permalink && strpos( $hub_content, $permalink ) === false ) {
                $result['orphaned']++;

                $commune = get_post_meta( $pid, $meta_prefix . 'commune', true ) ?: 'Unknown';
                $region  = get_post_meta( $pid, $meta_prefix . 'region', true ) ?: '';

                if ( $this->link_from_hub_page( $country_key, $pid, $commune, $region ) ) {
                    $result['fixed']++;
                    // Refresh hub content for next iteration
                    $hub_content = get_post_field( 'post_content', $hub_id );
                }
            }
        }

        error_log( "DBA GeoBot Anti-Orphan Audit [{$country_key}]: total={$result['total']}, orphaned={$result['orphaned']}, fixed={$result['fixed']}" );

        return $result;
    }
}
