<?php

namespace SugarCalendarBookings\UsageTracking;

use SugarCalendarBookings\Appointments\AppointmentModel;
use SugarCalendarBookings\Customers\CustomerModel;
use SugarCalendarBookings\Employees\EmployeeModel;
use SugarCalendarBookings\Locations\LocationModel;
use SugarCalendarBookings\Notifications\Emails\EmailDefaults;
use SugarCalendarBookings\Options;
use SugarCalendarBookings\Payments\PaymentModel;
use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Services\ServiceModel;
use SugarCalendarBookings\Support\Bootable;
use SugarCalendarBookings\Support\Database\QueryBuilder;
use SugarCalendarBookings\Support\Helpers\Helpers;
use WP_Theme;

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

/**
 * Usage Tracking functionality.
 *
 * Manages the enable/disable lifecycle and collects anonymous usage data.
 *
 * @since 1.4.0
 */
class UsageTracking implements Bootable {

	/**
	 * Initialize the usage tracking.
	 *
	 * @since 1.4.0
	 */
	public function init() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		// Schedule or cancel the task when the option changes.
		add_action(
			'update_option_' . Options::OPTION_NAME,
			function ( $old_value, $new_value ) {

				$old_disabled = ! empty( $old_value['misc']['disable_integrations'] );
				$new_disabled = ! empty( $new_value['misc']['disable_integrations'] );

				if ( $old_disabled === $new_disabled ) {
					return;
				}

				$task = new SendUsageTask();

				if ( ! $new_disabled ) {
					$task->init();
				} else {
					$task->cancel();
				}
			},
			10,
			2
		);
	}

	/**
	 * Whether usage tracking is enabled.
	 *
	 * @since 1.4.0
	 *
	 * @return bool
	 */
	public function is_enabled() {

		return ! Plugin::get( Options::class )->get( 'misc.disable_integrations' );
	}

	/**
	 * Get the User Agent string that will be sent to the API.
	 *
	 * @since 1.4.0
	 *
	 * @return string
	 */
	public function get_user_agent() {

		return Helpers::get_default_user_agent();
	}

	/**
	 * Get data for sending to the server.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	public function get_data() {

		global $wpdb;

		$theme_data = wp_get_theme();

		$data = array_merge(
			$this->get_environment_data( $wpdb, $theme_data ),
			$this->get_plugin_data(),
			$this->get_appointment_data(),
			$this->get_entity_counts(),
			$this->get_payment_data(),
			$this->get_settings_data(),
			$this->get_notifications_data(),
			$this->get_booking_form_data()
		);

		/**
		 * Filter the usage tracking data.
		 *
		 * @since 1.4.0
		 *
		 * @param array $data The usage tracking data.
		 */
		return (array) apply_filters( 'sugar_calendar_bookings_usage_tracking_usage_tracking_get_data', $data );
	}

	/**
	 * Get environment data.
	 *
	 * @since 1.4.0
	 *
	 * @param wpdb     $wpdb       WordPress database object.
	 * @param WP_Theme $theme_data Active theme data.
	 *
	 * @return array
	 */
	private function get_environment_data( $wpdb, $theme_data ) {

		return [
			'url'             => home_url(),
			'php_version'     => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION,
			'wp_version'      => get_bloginfo( 'version' ),
			'mysql_version'   => $wpdb->db_version(),
			'server_version'  => isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '',
			'is_ssl'          => is_ssl(),
			'is_multisite'    => is_multisite(),
			'sites_count'     => function_exists( 'get_blog_count' ) ? get_blog_count() : 1,
			'theme_name'      => $theme_data->name,
			'theme_version'   => $theme_data->version,
			'locale'          => get_locale(),
			'timezone_offset' => function_exists( 'wp_timezone_string' ) ? wp_timezone_string() : '',
			'active_plugins'  => $this->get_active_plugins(),
		];
	}

	/**
	 * Get plugin-specific data.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	private function get_plugin_data() {

		$activated_dates = get_option( 'sugar_calendar_bookings_activated', [] );
		$options         = Plugin::get( Options::class );

		return [
			'scbookings_version'             => SCBOOKINGS_PLUGIN_VERSION,
			'scbookings_activated'           => get_option( 'sugar_calendar_bookings_initial_activation_time', 0 ),
			'scbookings_license_key'         => $options->get( 'license.key', '' ),
			'scbookings_license_type'        => $options->get( 'license.type', 'lite' ),
			'scbookings_is_pro'              => sugar_calendar_bookings()->is_pro(),
			'scbookings_lite_installed_date' => ! empty( $activated_dates['lite'] ) ? $activated_dates['lite'] : false,
			'scbookings_pro_installed_date'  => ! empty( $activated_dates['pro'] ) ? $activated_dates['pro'] : false,
		];
	}

	/**
	 * Get appointment statistics.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	private function get_appointment_data() {

		$total = AppointmentModel::query()->count();

		// In-person: appointments with a location_id set.
		$in_person_count = AppointmentModel::query()
			->where( 'location_id', '>', 0, '%d' )
			->count();

		// Online: appointments with an online_location meta entry.
		$qb = new QueryBuilder();

		$online_count = $qb->table( 'appointments' )
			->join( 'meta', 'appointments.id', '=', 'meta.object_id' )
			->where( 'meta.object_type', '=', 'appointment', '%s' )
			->where( 'meta.meta_key', '=', 'online_location', '%s' )
			->count();

		return [
			'scbookings_total_appointments'     => $total,
			'scbookings_appointments_online'    => $online_count,
			'scbookings_appointments_in_person' => $in_person_count,
		];
	}

	/**
	 * Get entity counts.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	private function get_entity_counts() {

		return [
			'scbookings_total_customers' => CustomerModel::query()->count(),
			'scbookings_total_employees' => EmployeeModel::query()->count(),
			'scbookings_total_services'  => ServiceModel::query()->count(),
			'scbookings_total_locations' => LocationModel::query()->count(),
			'scbookings_total_payments'  => PaymentModel::query()->count(),
		];
	}

	/**
	 * Get payment configuration data.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	private function get_payment_data() {

		$options = Plugin::get( Options::class );

		return [
			'scbookings_gateway_stripe_enabled' => (bool) $options->get( 'payments.gateways.stripe.enabled', false ),
			'scbookings_gateway_stripe_mode'    => $options->get( 'stripe.test_mode', false ) ? 'test' : 'live',
		];
	}

	/**
	 * Get settings and configuration data.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	private function get_settings_data() {

		$options = Plugin::get( Options::class );

		return [
			'scbookings_default_appointment_status'  => $options->get( 'appointments.default_status', 'approved' ),
			'scbookings_min_advance_booking_enabled' => (bool) $options->get( 'appointments.advance_minimum', false ),
			'scbookings_min_advance_booking_days'    => (int) $options->get( 'appointments.advance_minimum_days', 1 ),
			'scbookings_max_advance_booking_enabled' => (bool) $options->get( 'appointments.advance_maximum', false ),
			'scbookings_max_advance_booking_days'    => (int) $options->get( 'appointments.advance_maximum_days', 31 ),
			'scbookings_currency'                    => $options->get( 'payments.currency', 'USD' ),
		];
	}

	/**
	 * Get notifications configuration data.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	private function get_notifications_data() {

		$options = Plugin::get( Options::class );
		$data    = [];

		foreach ( EmailDefaults::to_array() as $key => $defaults ) {

			// Skip non-email entries (from_email, from_name).
			if ( ! is_array( $defaults ) || ! isset( $defaults['enabled'] ) ) {
				continue;
			}

			$data[ 'scbookings_email_' . $key . '_enabled' ] = (bool) $options->get( "emails.{$key}.enabled", true );
		}

		return $data;
	}

	/**
	 * Get booking form display data.
	 *
	 * Checks post content for block, shortcode, and Elementor widget usage.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	private function get_booking_form_data() {

		global $wpdb;

		// Check for Gutenberg block usage (block name: scbookings/booking-form).
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
		$block_used = (bool) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->posts}
				WHERE post_status = 'publish'
				AND post_content LIKE %s",
				'%<!-- wp:scbookings/booking-form%'
			)
		);

		// Check for shortcode usage (shortcode: sugar_calendar_bookings_form).
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
		$shortcode_used = (bool) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->posts}
				WHERE post_status = 'publish'
				AND post_content LIKE %s",
				'%[sugar_calendar_bookings_form%'
			)
		);

		// Check for Elementor widget usage (widget name: sugar_calendar_booking_form).
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
		$elementor_used = (bool) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->postmeta} pm
				INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
				WHERE p.post_status = 'publish'
				AND pm.meta_key = %s
				AND pm.meta_value LIKE %s",
				'_elementor_data',
				'%sugar_calendar_booking_form%'
			)
		);

		return [
			'scbookings_booking_form_block_used'     => $block_used,
			'scbookings_booking_form_shortcode_used' => $shortcode_used,
			'scbookings_booking_form_elementor_used' => $elementor_used,
		];
	}

	/**
	 * Get the list of active plugins.
	 *
	 * @since 1.4.0
	 *
	 * @return array
	 */
	private function get_active_plugins() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		if ( ! function_exists( 'get_plugins' ) ) {
			include ABSPATH . '/wp-admin/includes/plugin.php';
		}

		$active_plugins = [];

		foreach ( get_mu_plugins() as $path => $plugin ) {
			$active_plugins[ $path ] = isset( $plugin['Version'] ) ? $plugin['Version'] : 'Not Set';
		}

		foreach ( get_plugins() as $path => $plugin ) {
			if ( is_plugin_active( $path ) ) {
				$active_plugins[ $path ] = isset( $plugin['Version'] ) ? $plugin['Version'] : 'Not Set';
			}
		}

		return $active_plugins;
	}
}
