<?php
/**
 * Créateurs du Mode Gardien — Vague 2 (Réputation)
 *
 * Trois boucliers pour la gestion de la réputation :
 *   1. Proof Extractor    — Isole les avis 5/5, crée des brouillons "Témoignage Client"
 *   2. Hybrid Responses   — Prépare les réponses aux avis (Co-pilote = draft, Auto-pilote = publish)
 *   3. Armored Reputation — Gestion de crise pour avis < 3 étoiles
 *
 * Réutilise les classes existantes sans duplication :
 *   - Google_My_Business_API  → get_reviews(), reply_to_review(), convert_google_review_to_avi_format()
 *   - Guardian_Response_Generator → generate(), generateWithJustification()
 *
 * @package Avision
 */

namespace Avision;

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

class Avision_Guardian_Creators {

    private const LOG_FILE = 'logs/guardian-creators.log';

    // ──────────────────────────────────────────────
    // Point d'entrée
    // ──────────────────────────────────────────────

    /**
     * Exécute les 3 boucliers de réputation pour un utilisateur.
     *
     * @param int   $user_id  ID utilisateur
     * @param array $profile  Ligne complète avi_saas_profiles
     * @return array{proofs: int, responses: int, crises: int}
     */
    public function run_wave2( int $user_id, array $profile ): array {
        $results = [ 'proofs' => 0, 'responses' => 0, 'crises' => 0 ];

        $token       = trim( (string) ( $profile['google_access_token'] ?? '' ) );
        $location_id = trim( (string) ( $profile['google_location_name'] ?? '' ) );

        if ( $token === '' || $location_id === '' ) {
            $this->log( 'DEBUG', "Wave2: skip user={$user_id} (token ou location manquant)" );
            return $results;
        }

        $profile_id = (int) ( $profile['id'] ?? 0 );
        // ── Timeout guard Wave 2 — évite blocage cron si Places API lente ──
        $prev_limit = (int) ini_get( 'max_execution_time' );
        @set_time_limit( 30 );
        try {
            $reviews = $this->fetch_recent_reviews( $token, $location_id, $profile );
        } catch ( \Throwable $e ) {
            error_log( '[AVI] Wave2 fetch_recent_reviews timeout/error: ' . $e->getMessage() );
            $reviews = array();
        } finally {
            @set_time_limit( $prev_limit > 0 ? $prev_limit : 0 );
        }
        if ( empty( $reviews ) ) {
            $this->log( 'WARN', "Wave2: aucun avis récent pour user={$user_id}, profile_id={$profile_id}. Vérifier token, location_id (format: accounts/xxx/locations/yyy) et API Google." );
            return $results;
        }

        foreach ( $reviews as $review ) {
            $avi_review = Google_My_Business_API::convert_google_review_to_avi_format( $review );
            $rating     = (int) ( $avi_review['rating'] ?? 5 );
            $review_id  = $avi_review['review_id'] ?? '';

            if ( $review_id === '' ) {
                continue;
            }

            if ( $this->is_review_already_processed( $profile_id, $review_id ) ) {
                continue;
            }

            // Bouclier 3 en premier : avis < 3 étoiles = urgence crise
            if ( $rating < 3 ) {
                $crisis = $this->trigger_armored_reputation( $user_id, $profile, $avi_review );
                if ( $crisis ) {
                    $results['crises']++;
                }
                continue;
            }

            // Bouclier 1 : avis 5/5 → Proof Extractor (témoignage)
            if ( $rating === 5 ) {
                $proof = $this->process_proof_extractor( $user_id, $profile, $avi_review );
                if ( $proof ) {
                    $results['proofs']++;
                }
            }

            // Bouclier 2 : tous les avis → réponse hybride
            $responded = $this->generate_hybrid_responses( $user_id, $profile, $avi_review );
            if ( $responded ) {
                $results['responses']++;
            }
        }

        $this->log( 'INFO', "Wave2 terminée: user={$user_id} proofs={$results['proofs']}, responses={$results['responses']}, crises={$results['crises']}" );
        return $results;
    }

    // ══════════════════════════════════════════════
    // BOUCLIER 1 — Proof Extractor (Témoignages 5/5)
    // ══════════════════════════════════════════════

    /**
     * Isole un avis 5/5 et crée un brouillon de post "Témoignage Client"
     * dans la table avi_saas_posts.
     *
     * @param int   $user_id
     * @param array $profile
     * @param array $review  Format AVI (review_id, reviewer_name, rating, text, created_at)
     * @return bool  true si le brouillon a été créé
     */
    public function process_proof_extractor( int $user_id, array $profile, array $review ): bool {
        if ( (int) ( $review['rating'] ?? 0 ) !== 5 ) {
            return false;
        }

        $review_text   = trim( (string) ( $review['text'] ?? '' ) );
        $reviewer_name = trim( (string) ( $review['reviewer_name'] ?? 'Client' ) );
        $review_id     = $review['review_id'] ?? '';
        $profile_id    = (int) ( $profile['id'] ?? 0 );
        $business_name = trim( (string) ( $profile['business_name'] ?? '' ) );

        if ( $review_text === '' ) {
            $this->log( 'DEBUG', "Proof Extractor: avis 5/5 sans texte, skip (review_id={$review_id})" );
            return false;
        }

        $title   = 'Témoignage Client — ' . $reviewer_name;
        $content = $this->build_testimonial_post( $reviewer_name, $review_text, $business_name );

        global $wpdb;
        $table = $wpdb->prefix . 'avi_saas_posts';

        $table_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
        if ( $table_exists !== $table ) {
            $this->log( 'WARN', "Proof Extractor: table {$table} inexistante" );
            return false;
        }

        $result = $wpdb->insert( $table, [
            'user_id'          => $user_id,
            'profile_id'       => $profile_id,
            'post_type'        => 'testimonial',
            'title'            => mb_substr( $title, 0, 500 ),
            'content'          => $content,
            'source_review_id' => $review_id,
            'status'           => 'draft',
            'created_at'       => current_time( 'mysql', true ),
        ], [ '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s' ] );

        if ( $result ) {
            $this->log( 'OK', "Proof Extractor: brouillon créé (review_id={$review_id}, reviewer={$reviewer_name})" );
            return true;
        }

        $this->log( 'ERROR', "Proof Extractor: INSERT échoué — {$wpdb->last_error}" );
        return false;
    }

    /**
     * Construit le contenu du post "Témoignage Client" optimisé SEO local.
     */
    private function build_testimonial_post( string $reviewer_name, string $review_text, string $business_name ): string {
        $lines = [];
        $lines[] = "⭐⭐⭐⭐⭐ Témoignage Client";
        $lines[] = "";
        $lines[] = "« {$review_text} »";
        $lines[] = "— {$reviewer_name}";
        $lines[] = "";
        $lines[] = "Merci {$reviewer_name} pour cette confiance ! Chez {$business_name}, chaque avis compte.";
        $lines[] = "";
        $lines[] = "#AvisClient #Recommandation #{$business_name}";

        return implode( "\n", $lines );
    }

    // ══════════════════════════════════════════════
    // BOUCLIER 2 — Hybrid Responses (Co-pilote / Auto-pilote)
    // ══════════════════════════════════════════════

    /**
     * Génère une réponse à un avis selon le mode de pilotage du profil.
     *
     * Co-pilote (pilot_reviews_mode = 'manual')  → draft dans avi_review_responses
     * Auto-pilote (pilot_reviews_mode = 'auto')   → publish via Google_My_Business_API::reply_to_review()
     *
     * Réutilise Guardian_Response_Generator::generate() pour la rédaction.
     *
     * @param int   $user_id
     * @param array $profile
     * @param array $review  Format AVI
     * @return bool
     */
    public function generate_hybrid_responses( int $user_id, array $profile, array $review ): bool {
        $profile_id    = (int) ( $profile['id'] ?? 0 );
        $business_name = trim( (string) ( $profile['business_name'] ?? '' ) );
        $city          = trim( (string) ( $profile['city'] ?? '' ) );
        $review_id     = $review['review_id'] ?? '';
        $reviewer_name = trim( (string) ( $review['reviewer_name'] ?? 'Client' ) );
        $rating        = (int) ( $review['rating'] ?? 5 );
        $review_text   = trim( (string) ( $review['text'] ?? '' ) );
        $language      = $review['language'] ?? 'fr';
        $pilot_mode    = strtolower( trim( (string) ( $profile['pilot_reviews_mode'] ?? 'manual' ) ) );

        if ( ! class_exists( __NAMESPACE__ . '\Guardian_Response_Generator' ) ) {
            $this->log( 'ERROR', "Hybrid Responses: Guardian_Response_Generator introuvable" );
            return false;
        }

        $generator = new Guardian_Response_Generator();
        $response_text = $generator->generate( [
            'stars'         => $rating,
            'language'      => $language,
            'review_text'   => $review_text,
            'reviewer_name' => $reviewer_name,
            'company'       => $business_name,
            'city'          => $city,
            'context'       => [
                'is_empty' => ( $review_text === '' ),
            ],
        ] );

        if ( empty( $response_text ) ) {
            $this->log( 'WARN', "Hybrid Responses: génération vide pour review_id={$review_id}" );
            return false;
        }

        $response_mode = ( $pilot_mode === 'auto' ) ? 'autopilot' : 'copilot';
        $status        = ( $pilot_mode === 'auto' ) ? 'approved' : 'draft';

        $saved = $this->save_review_response(
            $user_id, $profile_id, $review_id, $reviewer_name,
            $rating, $review_text, $response_text, $response_mode, $status, false
        );

        if ( ! $saved ) {
            return false;
        }

        // Auto-pilote : publier directement via l'API Google
        if ( $pilot_mode === 'auto' ) {
            $published = $this->publish_response_to_google( $profile, $review_id, $response_text );
            if ( $published ) {
                $this->mark_response_published( $profile_id, $review_id );
                $this->log( 'OK', "Auto-pilote: réponse publiée (review_id={$review_id}, {$rating}★)" );
            } else {
                $this->log( 'WARN', "Auto-pilote: publication échouée (review_id={$review_id})" );
            }
        } else {
            $this->log( 'OK', "Co-pilote: brouillon créé (review_id={$review_id}, {$rating}★)" );
        }

        return true;
    }

    // ══════════════════════════════════════════════
    // BOUCLIER 3 — Armored Reputation (Gestion de crise)
    // ══════════════════════════════════════════════

    /**
     * Pour tout avis < 3 étoiles :
     *   1. Génère une alerte REAL dans avi_security_logs
     *   2. Prépare une réponse de crise en brouillon urgent
     *
     * @param int   $user_id
     * @param array $profile
     * @param array $review  Format AVI (avis négatif)
     * @return bool
     */
    public function trigger_armored_reputation( int $user_id, array $profile, array $review ): bool {
        $profile_id    = (int) ( $profile['id'] ?? 0 );
        $business_name = trim( (string) ( $profile['business_name'] ?? '' ) );
        $city          = trim( (string) ( $profile['city'] ?? '' ) );
        $review_id     = $review['review_id'] ?? '';
        $reviewer_name = trim( (string) ( $review['reviewer_name'] ?? 'Client' ) );
        $rating        = (int) ( $review['rating'] ?? 1 );
        $review_text   = trim( (string) ( $review['text'] ?? '' ) );
        $language      = $review['language'] ?? 'fr';

        // 1. Alerte REAL dans avi_security_logs (signal 12 = Galerie / Réputation)
        $msg_fr = "Alerte Réputation : avis {$rating}★ de « {$reviewer_name} ». Gestion de crise requise.";
        $msg_en = "Reputation Alert: {$rating}★ review from \"{$reviewer_name}\". Crisis management required.";

        if ( $review_text !== '' ) {
            $excerpt = mb_substr( $review_text, 0, 100 );
            $msg_fr .= " Extrait : « {$excerpt} »";
            $msg_en .= " Excerpt: \"{$excerpt}\"";
        }

        $this->write_security_log( $user_id, 'real', 12, 'alert', $msg_fr, $msg_en );

        // 2. Réponse de crise via Guardian_Response_Generator
        $response_text = '';
        if ( class_exists( __NAMESPACE__ . '\Guardian_Response_Generator' ) ) {
            $generator     = new Guardian_Response_Generator();
            $response_text = $generator->generateWithJustification( [
                'stars'          => $rating,
                'language'       => $language,
                'review_text'    => $review_text,
                'reviewer_name'  => $reviewer_name,
                'company'        => $business_name,
                'city'           => $city,
                'for_validation' => true,
                'context'        => [
                    'is_empty' => ( $review_text === '' ),
                ],
            ] );
        }

        if ( empty( $response_text ) ) {
            $response_text = $this->get_fallback_crisis_response( $reviewer_name, $business_name, $city, $language );
        }

        // Toujours en brouillon pour validation humaine urgente (jamais auto-pilote pour une crise)
        $saved = $this->save_review_response(
            $user_id, $profile_id, $review_id, $reviewer_name,
            $rating, $review_text, $response_text, 'copilot', 'pending_review', true
        );

        if ( $saved ) {
            $this->log( 'ALERT', "Armored Reputation: crise {$rating}★ par « {$reviewer_name} » — brouillon urgent créé (review_id={$review_id})" );
        }

        return $saved;
    }

    /**
     * Réponse de crise par défaut si le générateur est indisponible.
     */
    private function get_fallback_crisis_response( string $reviewer, string $company, string $city, string $lang ): string {
        if ( $lang === 'fr' ) {
            return "Bonjour {$reviewer},\n\nNous sommes sincèrement désolés pour cette expérience. "
                 . "Chez {$company} à {$city}, la satisfaction de nos clients est notre priorité absolue. "
                 . "Nous aimerions comprendre ce qui s'est passé et trouver une solution. "
                 . "Pourriez-vous nous contacter directement afin que nous puissions en discuter ?\n\n"
                 . "Cordialement,\nL'équipe {$company}";
        }

        return "Dear {$reviewer},\n\nWe sincerely apologize for your experience. "
             . "At {$company} in {$city}, customer satisfaction is our top priority. "
             . "We would like to understand what happened and find a solution. "
             . "Could you please contact us directly so we can discuss this?\n\n"
             . "Best regards,\nThe {$company} Team";
    }

    // ══════════════════════════════════════════════
    // Helpers — API Google (via classe existante)
    // ══════════════════════════════════════════════

    /**
     * Récupère les avis récents via Google_My_Business_API (existante).
     *
     * @param string $token       Jeton OAuth Google.
     * @param string $location_id accounts/…/locations/…
     * @param array  $profile     Ligne avi_saas_profiles (google_place_id pour Places API).
     */
    private function fetch_recent_reviews( string $token, string $location_id, array $profile = array() ): array {
        if ( ! class_exists( __NAMESPACE__ . '\Google_My_Business_API' ) ) {
            $this->log( 'ERROR', 'Google_My_Business_API introuvable' );
            return array();
        }

        // Récupérer le place_id depuis le profil pour Places API (règle #173)
        global $wpdb;
        $_place_id = '';
        if ( isset( $profile['google_place_id'] ) && ! empty( $profile['google_place_id'] ) ) {
            $_place_id = trim( (string) $profile['google_place_id'] );
        } elseif ( isset( $profile['id'] ) && (int) $profile['id'] > 0 && isset( $wpdb ) && $wpdb ) {
            $_place_id = (string) $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT google_place_id FROM {$wpdb->prefix}avi_saas_profiles WHERE id = %d LIMIT 1",
                    (int) $profile['id']
                )
            );
            $_place_id = trim( $_place_id );
        }

        $api     = new Google_My_Business_API( $token, $location_id, $_place_id );
        $reviews = $api->get_reviews( 20 );

        return is_array( $reviews ) ? $reviews : array();
    }

    /**
     * Publie une réponse via Google_My_Business_API::reply_to_review() (existante).
     */
    private function publish_response_to_google( array $profile, string $review_id, string $response_text ): bool {
        $token       = trim( (string) ( $profile['google_access_token'] ?? '' ) );
        $location_id = trim( (string) ( $profile['google_location_name'] ?? '' ) );

        if ( $token === '' || $location_id === '' ) {
            return false;
        }

        if ( ! class_exists( __NAMESPACE__ . '\Google_My_Business_API' ) ) {
            return false;
        }

        $api = new Google_My_Business_API( $token, $location_id );
        return $api->reply_to_review( $review_id, $response_text );
    }

    // ══════════════════════════════════════════════
    // Helpers — Écriture BDD
    // ══════════════════════════════════════════════

    /**
     * Enregistre une réponse dans avi_review_responses.
     */
    private function save_review_response(
        int $user_id, int $profile_id, string $review_id, string $reviewer_name,
        int $rating, string $review_text, string $response_text,
        string $response_mode, string $status, bool $is_crisis
    ): bool {
        global $wpdb;
        $table = $wpdb->prefix . 'avi_review_responses';

        $table_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
        if ( $table_exists !== $table ) {
            $this->log( 'WARN', "save_review_response: table {$table} inexistante" );
            return false;
        }

        $result = $wpdb->replace( $table, [
            'user_id'          => $user_id,
            'profile_id'       => $profile_id,
            'google_review_id' => $review_id,
            'reviewer_name'    => mb_substr( $reviewer_name, 0, 255 ),
            'rating'           => $rating,
            'review_text'      => $review_text,
            'response_text'    => $response_text,
            'response_mode'    => $response_mode,
            'status'           => $status,
            'is_crisis'        => $is_crisis ? 1 : 0,
            'created_at'       => current_time( 'mysql', true ),
        ], [ '%d', '%d', '%s', '%s', '%d', '%s', '%s', '%s', '%s', '%d', '%s' ] );

        if ( $wpdb->last_error ) {
            $this->log( 'ERROR', "save_review_response: {$wpdb->last_error}" );
            return false;
        }

        return $result !== false;
    }

    /**
     * Marque une réponse comme publiée.
     */
    private function mark_response_published( int $profile_id, string $review_id ): void {
        global $wpdb;
        $table = $wpdb->prefix . 'avi_review_responses';

        $wpdb->update(
            $table,
            [
                'status'       => 'published',
                'published_at' => current_time( 'mysql', true ),
            ],
            [
                'profile_id'       => $profile_id,
                'google_review_id' => $review_id,
            ],
            [ '%s', '%s' ],
            [ '%d', '%s' ]
        );
    }

    /**
     * Vérifie si un avis a déjà été traité (évite les doublons).
     */
    private function is_review_already_processed( int $profile_id, string $review_id ): bool {
        global $wpdb;
        $table = $wpdb->prefix . 'avi_review_responses';

        $table_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
        if ( $table_exists !== $table ) {
            return false;
        }

        $exists = $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(*) FROM {$table} WHERE profile_id = %d AND google_review_id = %s",
            $profile_id, $review_id
        ) );

        return (int) $exists > 0;
    }

    // ══════════════════════════════════════════════
    // Écriture avi_security_logs
    // ══════════════════════════════════════════════

    private function write_security_log( int $user_id, string $event_type, int $signal_id, string $status, string $msg_fr, string $msg_en ): void {
        global $wpdb;
        $table = $wpdb->prefix . 'avi_security_logs';

        $table_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) );
        if ( $table_exists !== $table ) {
            return;
        }

        $wpdb->insert( $table, [
            'user_id'      => $user_id,
            'event_type'   => $event_type,
            'signal_id'    => $signal_id,
            'status'       => $status,
            'message_json' => wp_json_encode( [ 'fr' => $msg_fr, 'en' => $msg_en ], JSON_UNESCAPED_UNICODE ),
            'created_at'   => current_time( 'mysql', true ),
        ], [ '%d', '%s', '%d', '%s', '%s', '%s' ] );
    }

    // ══════════════════════════════════════════════
    // Logging
    // ══════════════════════════════════════════════

    private function log( string $level, string $message ): void {
        $line = sprintf( "[%s] [%s] %s\n", gmdate( 'Y-m-d H:i:s' ), $level, $message );
        $log_path = $this->get_log_path();
        if ( $log_path ) {
            $dir = dirname( $log_path );
            if ( ! is_dir( $dir ) ) {
                @wp_mkdir_p( $dir );
            }
            @file_put_contents( $log_path, $line, FILE_APPEND | LOCK_EX );
        }
        if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
            error_log( '[AVI Creators] [' . $level . '] ' . $message );
        }
    }

    private function get_log_path(): string {
        $plugin_dir = defined( 'AVISION_PLUGIN_DIR' ) ? AVISION_PLUGIN_DIR : ( dirname( __DIR__ ) . '/' );
        return $plugin_dir . self::LOG_FILE;
    }
}
