<?php
/**
 * Plugin Name:       Truebe - Fact-Based AI Chatbot
 * Plugin URI:        https://truebe.io
 * Description:       Gated Truth Architecture for WordPress. Your AI answers only from your own documents, every answer cited. Prevention, not detection.
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      7.4
 * Author:            Truebe
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       truebe-fact-based-ai-chatbot
 */

// Block direct access.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// Guard against double-loading or a name collision with another plugin.
if ( defined( 'TRUEBE_VERSION' ) ) {
	return;
}

define( 'TRUEBE_VERSION', '1.0.0' );
define( 'TRUEBE_PLUGIN_FILE', __FILE__ );
define( 'TRUEBE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'TRUEBE_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
define( 'TRUEBE_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
define( 'TRUEBE_CONNECT_URL',     'https://www.truebe.io/connect' );
define( 'TRUEBE_EXCHANGE_URL',    'https://www.truebe.io/api/connect/exchange' );
define( 'TRUEBE_FEEDBACK_URL',    'https://www.truebe.io/api/feedback' );

/**
 * Extend the nonce lifetime to a full day so admins don't hit "The link you
 * followed has expired" on pages left open during a normal work session.
 */
add_filter( 'nonce_life', 'truebe_nonce_life' );
function truebe_nonce_life() {
	return DAY_IN_SECONDS;
}

/**
 * Load a plugin class file from /includes once, only if its class isn't already declared.
 *
 * @param string $file  File name inside /includes.
 * @param string $class Class the file is expected to declare.
 */
function truebe_require( $file, $class ) {
	if ( class_exists( $class ) ) {
		return;
	}
	$path = TRUEBE_PLUGIN_DIR . 'includes/' . $file;
	if ( file_exists( $path ) ) {
		require_once $path;
	}
}

/**
 * Boot the plugin after all plugins are loaded, so collision checks see the full environment.
 */
function truebe_boot() {
	truebe_require( 'class-truebe-crypto.php', 'Truebe_Crypto' );
	truebe_require( 'class-truebe-plan.php', 'Truebe_Plan' );
	truebe_require( 'class-truebe-setup.php', 'Truebe_Setup' );
	truebe_require( 'class-truebe-seeds.php', 'Truebe_Seeds' );
	truebe_require( 'class-truebe-audit.php', 'Truebe_Audit' );
	truebe_require( 'class-truebe-intent.php', 'Truebe_Intent' );
	truebe_require( 'class-truebe-matcher.php', 'Truebe_Matcher' );
	truebe_require( 'class-truebe-validator.php', 'Truebe_Validator' );
	truebe_require( 'class-truebe-admin-upload.php', 'Truebe_Admin_Upload' );
	truebe_require( 'class-truebe-admin-seeds.php', 'Truebe_Admin_Seeds' );
	truebe_require( 'class-truebe-admin-chat.php', 'Truebe_Admin_Chat' );
	truebe_require( 'class-truebe-provider.php', 'Truebe_Provider' );
	truebe_require( 'class-truebe-documents.php', 'Truebe_Documents' );
	truebe_require( 'class-truebe-query.php', 'Truebe_Query' );
	truebe_require( 'class-truebe-querylog.php', 'Truebe_Query_Log' );
	truebe_require( 'class-truebe-gaps.php', 'Truebe_Gaps' );
	truebe_require( 'class-truebe-license.php', 'Truebe_License' );
	truebe_require( 'class-truebe-chatbot.php', 'Truebe_Chatbot' );
	truebe_require( 'class-truebe-admin-implement.php', 'Truebe_Admin_Implement' );
	truebe_require( 'class-truebe-admin-welcome.php', 'Truebe_Admin_Welcome' );
	truebe_require( 'class-truebe-review-ask.php', 'Truebe_Review_Ask' );
	truebe_require( 'class-truebe-deactivate-survey.php', 'Truebe_Deactivate_Survey' );

	if ( class_exists( 'Truebe_Seeds' ) && method_exists( 'Truebe_Seeds', 'maybe_upgrade' ) ) {
		Truebe_Seeds::maybe_upgrade();
	}
	if ( class_exists( 'Truebe_Setup' ) ) {
		Truebe_Setup::instance();
	}
	if ( class_exists( 'Truebe_Admin_Seeds' ) ) {
		Truebe_Admin_Seeds::init();
	}
	if ( class_exists( 'Truebe_Admin_Upload' ) ) {
		Truebe_Admin_Upload::init();
	}
	if ( class_exists( 'Truebe_Admin_Chat' ) ) {
		Truebe_Admin_Chat::init();
	}
	if ( class_exists( 'Truebe_License' ) ) {
		Truebe_License::init();
	}
	if ( class_exists( 'Truebe_Chatbot' ) ) {
		Truebe_Chatbot::init();
	}
	if ( class_exists( 'Truebe_Admin_Implement' ) ) {
		Truebe_Admin_Implement::init();
	}
	if ( class_exists( 'Truebe_Admin_Welcome' ) ) {
		Truebe_Admin_Welcome::init();
	}
	if ( class_exists( 'Truebe_Review_Ask' ) ) {
		Truebe_Review_Ask::init();
	}
	if ( class_exists( 'Truebe_Deactivate_Survey' ) ) {
		Truebe_Deactivate_Survey::init();
	}
}
add_action( 'plugins_loaded', 'truebe_boot' );

/**
 * Add a "Get Started" link to the plugin's row on the Plugins page, so a new
 * user has an obvious path into the plugin instead of hunting for the sidebar icon.
 *
 * @param array $links Existing action links.
 * @return array
 */
function truebe_plugin_action_links( $links ) {
	$url  = admin_url( 'admin.php?page=truebe-welcome' );
	$link = '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Get Started', 'truebe-fact-based-ai-chatbot' ) . '</a>';
	array_unshift( $links, $link );
	return $links;
}
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'truebe_plugin_action_links' );

/**
 * On first activation, redirect the user to the Getting Started page so a new
 * install lands on guidance instead of the Plugins list. Skipped for bulk
 * plugin activations, where a redirect would be disruptive.
 */
function truebe_activation_redirect() {
	if ( get_option( 'truebe_activation_redirect', false ) ) {
		delete_option( 'truebe_activation_redirect' );
		if ( ! isset( $_GET['activate-multi'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- core sets this flag on bulk activation; read-only check, no data change.
			wp_safe_redirect( admin_url( 'admin.php?page=truebe-welcome' ) );
			exit;
		}
	}
}
add_action( 'admin_init', 'truebe_activation_redirect' );

/**
 * Per-site table setup, called once for the current blog. Guarded so a
 * partial environment can't fatal. Shared by both single-site activation
 * and each site's pass during a network activation.
 */
function truebe_activate_single_site() {
	truebe_require( 'class-truebe-seeds.php', 'Truebe_Seeds' );
	if ( class_exists( 'Truebe_Seeds' ) && method_exists( 'Truebe_Seeds', 'install' ) ) {
		Truebe_Seeds::install();
	}
	truebe_require( 'class-truebe-gaps.php', 'Truebe_Gaps' );
	if ( class_exists( 'Truebe_Gaps' ) && method_exists( 'Truebe_Gaps', 'install' ) ) {
		Truebe_Gaps::install();
	}
	truebe_require( 'class-truebe-audit.php', 'Truebe_Audit' );
	if ( class_exists( 'Truebe_Audit' ) && method_exists( 'Truebe_Audit', 'install' ) ) {
		Truebe_Audit::install();
	}
	truebe_require( 'class-truebe-querylog.php', 'Truebe_Query_Log' );
	if ( class_exists( 'Truebe_Query_Log' ) && method_exists( 'Truebe_Query_Log', 'install' ) ) {
		Truebe_Query_Log::install();
	}
	add_option( 'truebe_activation_redirect', true );
}

/**
 * Activation: on a normal single-site install this just sets up the current
 * site. On Multisite, if network-activated ($network_wide true), it installs
 * tables for every site in the network individually, since each site keeps
 * its own isolated Fact Library, gaps, and audit log — a chatbot answer from
 * one location must never leak into another.
 *
 * @param bool $network_wide True if activated network-wide via Network Admin.
 */
function truebe_activate( $network_wide = false ) {
	if ( is_multisite() && $network_wide ) {
		$site_ids = get_sites( array( 'fields' => 'ids' ) );
		foreach ( $site_ids as $site_id ) {
			switch_to_blog( $site_id );
			truebe_activate_single_site();
			restore_current_blog();
		}
		return;
	}
	truebe_activate_single_site();
}
register_activation_hook( __FILE__, 'truebe_activate' );

/**
 * When a new site is added to the network after Truebe was already
 * network-activated, give that new site its own tables automatically.
 */
function truebe_new_site_activation( $new_site ) {
	if ( ! is_plugin_active_for_network( TRUEBE_PLUGIN_BASENAME ) ) {
		return;
	}
	switch_to_blog( $new_site->blog_id );
	truebe_activate_single_site();
	restore_current_blog();
}
add_action( 'wp_initialize_site', 'truebe_new_site_activation' );

/**
 * Deactivation: clear scheduled events for the current site (or every site,
 * on network-wide deactivation). Leaves data intact.
 */
function truebe_deactivate_single_site() {
	wp_clear_scheduled_hook( 'truebe_license_daily_ping' );
	wp_clear_scheduled_hook( 'truebe_process_document' );
	wp_clear_scheduled_hook( 'truebe_gaps_nightly' );
}

function truebe_deactivate( $network_wide = false ) {
	if ( is_multisite() && $network_wide ) {
		$site_ids = get_sites( array( 'fields' => 'ids' ) );
		foreach ( $site_ids as $site_id ) {
			switch_to_blog( $site_id );
			truebe_deactivate_single_site();
			restore_current_blog();
		}
		return;
	}
	truebe_deactivate_single_site();
}
register_deactivation_hook( __FILE__, 'truebe_deactivate' );