<?php
/**
 * DBA GeoBot Dedupe — Commune-level duplicate detection (country-agnostic)
 *
 * Prevents the same commune from being written about twice within
 * a configurable cooldown window. Works identically for France,
 * Italy, Spain, Portugal — just pass the $country_key.
 *
 * ═══════════════════════════════════════════════════════════════════════
 *  ZERO CONFLICT: Each country has its own history option key
 *  (e.g. dba_geo_france_dedupe_history, dba_geo_italy_dedupe_history)
 * ═══════════════════════════════════════════════════════════════════════
 *
 * @since 2.8.0
 */

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

class DBA_GeoBot_Dedupe {

    const MAX_HISTORY_DAYS    = 60;  // Keep 60 days of history (communes rotate slower than PE news)
    const COOLDOWN_DAYS       = 14;  // Don't repeat a commune within 14 days

    /* ─────────────────────────────────────────────────────────────
     *  PUBLIC API
     * ───────────────────────────────────────────────────────────── */

    /**
     * Validate a commune candidate and reserve it if accepted.
     *
     * @param string $country_key  'france', 'italy', etc.
     * @param array  $item         { 'date' => 'Y-m-d', 'commune' => 'Nantes' }
     * @return array { 'ok' => bool, 'reason' => string }
     */
    public static function validate_and_reserve( string $country_key, array $item ) {

        $date    = ! empty( $item['date'] ) ? $item['date'] : current_time( 'Y-m-d' );
        $commune = trim( $item['commune'] ?? '' );

        if ( $commune === '' ) {
            return array( 'ok' => false, 'reason' => 'Commune name is empty' );
        }

        $slug = DBA_GeoBot_Registry::normalize_commune( $commune );
        $history = self::get_history( $country_key );

        // Check same-day
        $today_communes = $history['days'][ $date ]['communes'] ?? array();
        if ( in_array( $slug, $today_communes, true ) ) {
            return array( 'ok' => false, 'reason' => "Commune '{$commune}' already published today" );
        }

        // Check cooldown (last N days)
        $cooldown_start = date( 'Y-m-d', strtotime( "-" . self::COOLDOWN_DAYS . " days", strtotime( $date ) ) );
        foreach ( $history['days'] as $hist_date => $day_data ) {
            if ( $hist_date >= $cooldown_start && $hist_date < $date ) {
                $past_communes = $day_data['communes'] ?? array();
                if ( in_array( $slug, $past_communes, true ) ) {
                    return array( 'ok' => false, 'reason' => "Commune '{$commune}' was published on {$hist_date} (within " . self::COOLDOWN_DAYS . "-day cooldown)" );
                }
            }
        }

        // Reserve it
        if ( ! isset( $history['days'][ $date ] ) ) {
            $history['days'][ $date ] = array( 'communes' => array() );
        }
        $history['days'][ $date ]['communes'][] = $slug;

        // Prune old entries
        $history = self::prune_history( $history );

        self::save_history( $country_key, $history );

        return array( 'ok' => true, 'reason' => 'Accepted' );
    }

    /**
     * Pick the next commune to write about from the active list.
     * Prioritizes communes that haven't been covered in the longest time.
     *
     * @param string $country_key
     * @return array|null Commune data array or null if all exhausted.
     */
    public static function pick_next_commune( string $country_key ) {

        $active   = DBA_GeoBot_Registry::get_active_communes( $country_key );
        $history  = self::get_history( $country_key );
        $today    = current_time( 'Y-m-d' );

        // Build a "last published" index
        $last_pub = array();
        foreach ( $history['days'] as $date => $day_data ) {
            foreach ( ( $day_data['communes'] ?? array() ) as $slug ) {
                $last_pub[ $slug ] = $date;
            }
        }

        // Already used today
        $today_communes = $history['days'][ $today ]['communes'] ?? array();

        // Score each commune: lower = longer since last publish = higher priority
        $candidates = array();
        foreach ( $active as $commune_data ) {
            $slug = DBA_GeoBot_Registry::normalize_commune( $commune_data['commune'] );

            // Skip if already used today
            if ( in_array( $slug, $today_communes, true ) ) continue;

            // Skip if within cooldown
            if ( isset( $last_pub[ $slug ] ) ) {
                $cooldown_start = date( 'Y-m-d', strtotime( "-" . self::COOLDOWN_DAYS . " days" ) );
                if ( $last_pub[ $slug ] >= $cooldown_start ) continue;
            }

            // Priority: never published = 0 (highest), else days since last publish
            $last = $last_pub[ $slug ] ?? '2000-01-01';
            $days_ago = (int) ( ( strtotime( $today ) - strtotime( $last ) ) / 86400 );

            $candidates[] = array(
                'commune_data' => $commune_data,
                'slug'         => $slug,
                'days_ago'     => $days_ago,
            );
        }

        if ( empty( $candidates ) ) return null;

        // Sort by days_ago descending (longest ago first), with randomization for ties
        usort( $candidates, function( $a, $b ) {
            $diff = $b['days_ago'] - $a['days_ago'];
            return $diff !== 0 ? $diff : random_int( -1, 1 );
        });

        return $candidates[0]['commune_data'];
    }

    /* ─────────────────────────────────────────────────────────────
     *  HISTORY STORAGE
     * ───────────────────────────────────────────────────────────── */

    public static function get_history( string $country_key ) {
        $config = DBA_GeoBot_Registry::get_country( $country_key );
        if ( ! $config ) return array( 'days' => array() );
        $history = get_option( $config['history_option'], array() );
        if ( empty( $history['days'] ) ) {
            $history['days'] = array();
        }
        return $history;
    }

    private static function save_history( string $country_key, array $history ) {
        $config = DBA_GeoBot_Registry::get_country( $country_key );
        if ( ! $config ) return;
        update_option( $config['history_option'], $history, false );
    }

    private static function prune_history( array $history ) {
        $cutoff = date( 'Y-m-d', strtotime( '-' . self::MAX_HISTORY_DAYS . ' days' ) );
        foreach ( $history['days'] as $date => $data ) {
            if ( $date < $cutoff ) {
                unset( $history['days'][ $date ] );
            }
        }
        return $history;
    }

    /**
     * Get stats for admin display.
     */
    public static function get_stats( string $country_key ) {
        $history  = self::get_history( $country_key );
        $total    = 0;
        $last_30  = 0;
        $cutoff   = date( 'Y-m-d', strtotime( '-30 days' ) );

        foreach ( $history['days'] as $date => $data ) {
            $count = count( $data['communes'] ?? array() );
            $total += $count;
            if ( $date >= $cutoff ) $last_30 += $count;
        }

        $all_communes  = DBA_GeoBot_Registry::get_commune_names( $country_key );
        $covered       = array();
        foreach ( $history['days'] as $data ) {
            foreach ( ( $data['communes'] ?? array() ) as $slug ) {
                $covered[ $slug ] = true;
            }
        }

        return array(
            'total_published'    => $total,
            'last_30_days'       => $last_30,
            'communes_covered'   => count( $covered ),
            'communes_total'     => count( $all_communes ),
            'coverage_pct'       => count( $all_communes ) > 0
                ? round( count( $covered ) / count( $all_communes ) * 100, 1 )
                : 0,
        );
    }

    /**
     * Reset history for a country (admin action).
     */
    public static function reset_history( string $country_key ) {
        self::save_history( $country_key, array( 'days' => array() ) );
    }
}
