<?php
/**
 * Volade Gamification — XP, niveaux, badges, streaks
 *
 * @package Volade\SDK
 * @license GPL-2.0-or-later
 */

trait Volade_Gamification {

	private $xp_rules          = array();
	private $badge_definitions = array();

	public function init_gamification() {
		$this->xp_rules = array(
			'login'               => 5,
			'register'            => 50,
			'daily_visit'         => 2,
			'install'             => 50,
			'referral'            => 100,
			'review'              => 30,
			'share'               => 20,
			'badge_earned'        => 25,
			'onboarding_complete' => 30,
		);

		$this->badge_definitions = $this->build_badge_definitions();

		add_action( 'volade_daily_cron', array( $this, 'process_daily_streaks' ) );
		add_action( 'wp_ajax_volade_add_xp', array( $this, 'ajax_add_xp' ) );
	}

	/**
	 * @return array<string, array{name:string,desc:string,icon:string,require:string,count?:int}>
	 */
	private function build_badge_definitions() {
		return array(
			'early_bird'      => array(
				'name'    => __( 'Pionnier', 'core-version-switcher-by-volade' ),
				'desc'    => __( 'A rejoint Volade la première année.', 'core-version-switcher-by-volade' ),
				'icon'    => '🐦',
				'require' => 'early_bird',
			),
			'social'          => array(
				'name'    => __( 'Papillon social', 'core-version-switcher-by-volade' ),
				'desc'    => __( 'A parrainé 5 amis.', 'core-version-switcher-by-volade' ),
				'icon'    => '🦋',
				'require' => 'referrals',
				'count'   => 5,
			),
			'veteran'         => array(
				'name'    => __( 'Vétéran', 'core-version-switcher-by-volade' ),
				'desc'    => __( 'A atteint le niveau 10.', 'core-version-switcher-by-volade' ),
				'icon'    => '⭐',
				'require' => 'level',
				'count'   => 10,
			),
			'collector'       => array(
				'name'    => __( 'Collectionneur', 'core-version-switcher-by-volade' ),
				'desc'    => __( 'A installé 5 plugins Volade.', 'core-version-switcher-by-volade' ),
				'icon'    => '📦',
				'require' => 'installs',
				'count'   => 5,
			),
			'streak_7'        => array(
				'name'    => __( 'Guerrier hebdomadaire', 'core-version-switcher-by-volade' ),
				'desc'    => __( 'Série de 7 jours.', 'core-version-switcher-by-volade' ),
				'icon'    => '🔥',
				'require' => 'streak',
				'count'   => 7,
			),
			'streak_30'       => array(
				'name'    => __( 'Légende mensuelle', 'core-version-switcher-by-volade' ),
				'desc'    => __( 'Série de 30 jours.', 'core-version-switcher-by-volade' ),
				'icon'    => '💎',
				'require' => 'streak',
				'count'   => 30,
			),
			'referral_master' => array(
				'name'    => __( 'Maître du parrainage', 'core-version-switcher-by-volade' ),
				'desc'    => __( 'A parrainé 20 amis.', 'core-version-switcher-by-volade' ),
				'icon'    => '👑',
				'require' => 'referrals',
				'count'   => 20,
			),
		);
	}

	/**
	 * @return array<string, array{name:string,desc:string,icon:string,require:string,count?:int}>
	 */
	private function get_badge_definitions() {
		if ( empty( $this->badge_definitions ) ) {
			$this->badge_definitions = $this->build_badge_definitions();
		}
		return $this->badge_definitions;
	}

	public function get_badge_name( $badge_key ) {
		$key = sanitize_key( $badge_key );
		$def = $this->get_badge_definitions()[ $key ] ?? array();
		return $def['name'] ?? $badge_key;
	}

	public function enrich_badge( array $badge ) {
		$key = sanitize_key( $badge['badge_key'] ?? $badge['key'] ?? '' );
		if ( '' === $key ) {
			return $badge;
		}

		$def = $this->get_badge_definitions()[ $key ] ?? array();

		return array_merge(
			array(
				'key'       => $key,
				'badge_key' => $key,
			),
			$def,
			$badge,
			$def
		);
	}

	public function add_xp( $user_id, $action, $extra = 0 ) {
		global $wpdb;

		$base = isset( $this->xp_rules[ $action ] ) ? $this->xp_rules[ $action ] : 0;
		if ( $base <= 0 ) {
			return null;
		}
		$total = $base + $extra;

		$user = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT xp, level FROM {$wpdb->prefix}volade_users WHERE id = %d",
				$user_id
			)
		);

		if ( ! $user ) {
			return;
		}

		$new_xp    = $user->xp + $total;
		$new_level = $this->calculate_level( $new_xp );

		$wpdb->update(
			"{$wpdb->prefix}volade_users",
			array(
				'xp'         => $new_xp,
				'level'      => $new_level,
				'updated_at' => current_time( 'mysql' ),
			),
			array( 'id' => $user_id )
		);

		if ( class_exists( 'Volade_SDK' ) ) {
			$sdk = Volade_SDK::get_instance();
			if ( $sdk && method_exists( $sdk, 'clear_user_data_cache' ) ) {
				$sdk->clear_user_data_cache( $user_id );
			}
		}

		$this->log_event(
			$user_id,
			'xp_earned',
			array(
				'action' => $action,
				'amount' => $total,
				'total'  => $new_xp,
			)
		);

		if ( $new_level > $user->level ) {
			$this->log_event(
				$user_id,
				'level_up',
				array(
					'old_level' => $user->level,
					'new_level' => $new_level,
				)
			);
		}

		$this->check_badges( $user_id );

		return array(
			'xp_earned' => $total,
			'total_xp'  => $new_xp,
			'level'     => $new_level,
			'level_up'  => $new_level > $user->level,
		);
	}

	/**
	 * Attribue un montant d'XP personnalisé (missions, bonus…).
	 *
	 * @param array<string, mixed> $event_data
	 * @return array<string, mixed>|null
	 */
	public function grant_xp( $user_id, $amount, $reason = 'mission', $event_data = array() ) {
		global $wpdb;

		$amount = (int) $amount;
		if ( $amount <= 0 ) {
			return null;
		}

		$user = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT xp, level FROM {$wpdb->prefix}volade_users WHERE id = %d",
				$user_id
			)
		);

		if ( ! $user ) {
			return null;
		}

		$new_xp    = $user->xp + $amount;
		$new_level = $this->calculate_level( $new_xp );

		$wpdb->update(
			"{$wpdb->prefix}volade_users",
			array(
				'xp'         => $new_xp,
				'level'      => $new_level,
				'updated_at' => current_time( 'mysql' ),
			),
			array( 'id' => $user_id )
		);

		if ( class_exists( 'Volade_SDK' ) ) {
			$sdk = Volade_SDK::get_instance();
			if ( $sdk && method_exists( $sdk, 'clear_user_data_cache' ) ) {
				$sdk->clear_user_data_cache( $user_id );
			}
		}

		$this->log_event(
			$user_id,
			'xp_earned',
			array_merge(
				array(
					'action' => $reason,
					'amount' => $amount,
					'total'  => $new_xp,
				),
				$event_data
			)
		);

		if ( $new_level > $user->level ) {
			$this->log_event(
				$user_id,
				'level_up',
				array(
					'old_level' => $user->level,
					'new_level' => $new_level,
				)
			);
		}

		$this->check_badges( $user_id );

		return array(
			'xp_earned' => $amount,
			'total_xp'  => $new_xp,
			'level'     => $new_level,
			'level_up'  => $new_level > $user->level,
		);
	}

	public function process_daily_streaks() {
		global $wpdb;
		$yesterday = wp_date( 'Y-m-d', current_time( 'timestamp' ) - DAY_IN_SECONDS );
		$today     = current_time( 'Y-m-d' );

		$users = $wpdb->get_results(
			"SELECT id, streak, last_activity FROM {$wpdb->prefix}volade_users 
             WHERE last_activity IS NOT NULL"
		);

		foreach ( $users as $user ) {
			$last = wp_date( 'Y-m-d', strtotime( $user->last_activity ) );

			if ( $last === $today ) {
				continue;
			}

			if ( $last === $yesterday ) {
				$this->add_xp( $user->id, 'daily_visit' );
			} else {
				$wpdb->update(
					"{$wpdb->prefix}volade_users",
					array(
						'streak'     => 0,
						'updated_at' => current_time( 'mysql' ),
					),
					array( 'id' => $user->id )
				);
			}
		}
	}

	public function record_activity( $user_id ) {
		global $wpdb;
		$today = current_time( 'Y-m-d' );

		$user = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT last_activity, streak FROM {$wpdb->prefix}volade_users WHERE id = %d",
				$user_id
			)
		);

		if ( ! $user ) {
			return;
		}

		$last = $user->last_activity ? wp_date( 'Y-m-d', strtotime( $user->last_activity ) ) : '';

		if ( $last === $today ) {
			return;
		}

		if ( $last === wp_date( 'Y-m-d', current_time( 'timestamp' ) - DAY_IN_SECONDS ) ) {
			$new_streak = $user->streak + 1;
		} else {
			$new_streak = 1;
		}

		$wpdb->update(
			"{$wpdb->prefix}volade_users",
			array(
				'last_activity' => current_time( 'mysql' ),
				'streak'        => $new_streak,
				'updated_at'    => current_time( 'mysql' ),
			),
			array( 'id' => $user_id )
		);

		$this->add_xp( $user_id, 'daily_visit' );
		$this->check_badges( $user_id );
	}

	private function calculate_level( $xp ) {
		$xp = max( 0, (int) $xp );
		return max( 1, (int) floor( $xp / 100 ) + 1 );
	}

	/**
	 * Aligne le niveau stocké sur l'XP réel (évite les écarts après migrations / tests).
	 */
	public function sync_user_level( $user_id ) {
		global $wpdb;
		$xp = (int) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT xp FROM {$wpdb->prefix}volade_users WHERE id = %d",
				$user_id
			)
		);
		if ( ! $xp && 0 !== $xp ) {
			return;
		}
		$level = $this->calculate_level( $xp );
		$wpdb->update(
			"{$wpdb->prefix}volade_users",
			array(
				'level'      => $level,
				'updated_at' => current_time( 'mysql' ),
			),
			array( 'id' => $user_id )
		);
		if ( class_exists( 'Volade_SDK' ) ) {
			$sdk = Volade_SDK::get_instance();
			if ( $sdk && method_exists( $sdk, 'clear_user_data_cache' ) ) {
				$sdk->clear_user_data_cache( $user_id );
			}
		}
		return $level;
	}

	public function get_level_xp_requirements( $level ) {
		$level        = max( 1, (int) $level );
		$xp_for_level = ( $level - 1 ) * 100;
		return array(
			'current' => $xp_for_level,
			'next'    => $level * 100,
		);
	}

	public function get_user_badges( $user_id ) {
		global $wpdb;
		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT badge_key, earned_at FROM {$wpdb->prefix}volade_badges WHERE user_id = %d",
				$user_id
			),
			ARRAY_A
		);

		$badges = array();
		foreach ( $rows as $row ) {
			$badges[] = $this->enrich_badge(
				array(
					'key'       => $row['badge_key'],
					'badge_key' => $row['badge_key'],
					'earned_at' => $row['earned_at'],
				)
			);
		}
		return $badges;
	}

	private function check_badges( $user_id ) {
		global $wpdb;
		$user = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT level, streak, xp, created_at FROM {$wpdb->prefix}volade_users WHERE id = %d",
				$user_id
			)
		);

		if ( ! $user ) {
			return;
		}

		$referral_count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->prefix}volade_referrals WHERE referrer_id = %d AND status = 'converted'",
				$user_id
			)
		);

		$plugin_count = (int) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(DISTINCT plugin_slug) FROM {$wpdb->prefix}volade_events WHERE user_id = %d AND event_type = 'plugin_active' AND plugin_slug != ''",
				$user_id
			)
		);

		foreach ( $this->get_badge_definitions() as $key => $def ) {
			$has = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT id FROM {$wpdb->prefix}volade_badges WHERE user_id = %d AND badge_key = %s",
					$user_id,
					$key
				)
			);
			if ( $has ) {
				continue;
			}

			$earn = false;
			switch ( $def['require'] ?? '' ) {
				case 'level':
					$earn = $user->level >= $def['count'];
					break;
				case 'streak':
					$earn = $user->streak >= $def['count'];
					break;
				case 'referrals':
					$earn = $referral_count >= $def['count'];
					break;
				case 'installs':
					$earn = $plugin_count >= $def['count'];
					break;
				case 'early_bird':
					$earn = $user->created_at && (int) gmdate( 'Y', strtotime( $user->created_at ) ) <= 2027;
					break;
			}

			if ( $earn ) {
				$wpdb->insert(
					"{$wpdb->prefix}volade_badges",
					array(
						'user_id'   => $user_id,
						'badge_key' => $key,
						'earned_at' => current_time( 'mysql' ),
					)
				);
				$this->add_xp( $user_id, 'badge_earned' );
				$this->log_event( $user_id, 'badge_earned', array( 'badge_key' => $key ) );
			}
		}
	}

	private function log_event( $user_id, $event_type, $event_data = array(), $plugin_slug = '' ) {
		global $wpdb;
		$wpdb->insert(
			"{$wpdb->prefix}volade_events",
			array(
				'user_id'     => $user_id,
				'event_type'  => $event_type,
				'event_data'  => wp_json_encode( $event_data ),
				'plugin_slug' => $plugin_slug ?: ( $this->plugin_slug ?? '' ),
				'ip_address'  => $_SERVER['REMOTE_ADDR'] ?? '',
				'created_at'  => current_time( 'mysql' ),
			)
		);
	}

	public function ajax_add_xp() {
		check_ajax_referer( 'volade_nonce', 'nonce' );
		$user = $this->get_current_user();
		if ( ! $user ) {
			wp_send_json_error( 'Not authenticated' );
		}
		$action = sanitize_text_field( $_POST['action_name'] ?? '' );
		$result = $this->add_xp( $user['id'], $action );
		wp_send_json_success( $result );
	}

	public function rest_add_xp( $request ) {
		$user = $this->get_current_user();
		if ( ! $user ) {
			return new WP_REST_Response( array( 'error' => 'Not authenticated' ), 401 );
		}

		$rate_key = 'volade_xp_' . (int) $user['id'];
		$count    = (int) get_transient( $rate_key );
		if ( $count > 30 ) {
			return new WP_REST_Response( array( 'error' => 'Rate limit exceeded' ), 429 );
		}
		set_transient( $rate_key, $count + 1, HOUR_IN_SECONDS );

		$params = $request->get_params();
		$action = sanitize_key( $params['action'] ?? '' );
		$result = $this->add_xp( $user['id'], $action );
		if ( null === $result ) {
			return new WP_REST_Response( array( 'error' => 'Invalid action' ), 400 );
		}
		return new WP_REST_Response( $result, 200 );
	}

	public function get_all_badge_definitions() {
		return $this->get_badge_definitions();
	}

	public function track_plugin_active( $user_id, $plugin_slug ) {
		if ( ! $user_id || ! $plugin_slug ) {
			return;
		}
		global $wpdb;
		$seen = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT id FROM {$wpdb->prefix}volade_events WHERE user_id = %d AND event_type = 'plugin_active' AND plugin_slug = %s LIMIT 1",
				$user_id,
				$plugin_slug
			)
		);
		if ( $seen ) {
			return;
		}
		$this->log_event( $user_id, 'plugin_active', array( 'plugin' => $plugin_slug ), $plugin_slug );
		$this->check_badges( $user_id );
	}
}
