<?php

/**
 * LolaCore — Onboarding state and provider-transition detection.
 *
 * @package LolaCore
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\Chat;

use LolaCore\Admin\Settings;

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

/**
 * Tracks onboarding flags and the "moment of return" after Connectors setup.
 */
class OnboardingFlow {

	private const CONFIG_FIRST_GREETING_DONE = 'first_real_greeting_done';
	private const USER_META_HAD_PROVIDER     = 'lolacore_had_provider';
	private const TRANSIENT_PREFIX           = 'lolacore_first_greeting_';

	/**
	 * Register admin hooks.
	 */
	public function register(): void {
		\add_action( 'admin_init', array( $this, 'trackProviderTransition' ), 5 );
		\add_filter( 'rest_post_dispatch', array( $this, 'trackProviderOnSettingsSave' ), 10, 3 );
	}

	/**
	 * Whether a connector API key is stored (no live API probe).
	 *
	 * Used for onboarding UI/sync so the chat unlocks as soon as the user saves
	 * a key in Settings → Connectors (e.g. DeepSeek), without waiting for
	 * ListModelsApiBasedProviderAvailability network checks or a full reload.
	 */
	public static function hasStoredProviderCredentials(): bool {
		if ( ! \function_exists( 'wp_get_connectors' ) ) {
			return false;
		}

		foreach ( \wp_get_connectors() as $connector_data ) {
			if ( ( $connector_data['type'] ?? '' ) !== 'ai_provider' ) {
				continue;
			}

			$auth = $connector_data['authentication'] ?? array();
			if ( ( $auth['method'] ?? '' ) !== 'api_key' || empty( $auth['setting_name'] ) ) {
				continue;
			}

			if ( \function_exists( '_wp_connectors_get_api_key_source' ) ) {
				$key_source = \_wp_connectors_get_api_key_source(
					$auth['setting_name'],
					$auth['env_var_name'] ?? '',
					$auth['constant_name'] ?? ''
				);
				if ( 'none' !== $key_source ) {
					return true;
				}
				continue;
			}

			$api_key = \get_option( $auth['setting_name'], '' );
			if ( \is_string( $api_key ) && $api_key !== '' ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Whether the UI should treat an AI provider as available (stored key or live probe).
	 */
	public static function hasProviderForChat(): bool {
		return self::hasStoredProviderCredentials() || self::isProviderConfigured();
	}

	/**
	 * Whether any WP AI provider passes a live configuration probe.
	 */
	public static function isProviderConfigured(): bool {
		if ( ! class_exists( '\\WordPress\\AiClient\\AiClient' ) ) {
			return false;
		}

		try {
			$registry = \WordPress\AiClient\AiClient::defaultRegistry();
			foreach ( $registry->getRegisteredProviderIds() as $providerId ) {
				if ( $registry->isProviderConfigured( $providerId ) ) {
					return true;
				}
			}
		} catch ( \Throwable $e ) {
			return false;
		}

		return false;
	}

	/**
	 * @return bool
	 */
	public static function isOnboardingComplete(): bool {
		return Settings::getConfig( 'onboarding_complete', '0' ) === '1';
	}

	/**
	 * @return bool
	 */
	public static function isFirstRealGreetingDone(): bool {
		return Settings::getConfig( self::CONFIG_FIRST_GREETING_DONE, '0' ) === '1';
	}

	/**
	 * Persist first-real-greeting completion (idempotent).
	 */
	public static function markFirstRealGreetingDone(): void {
		global $wpdb;

		$table = $wpdb->prefix . 'lolacore_config';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->replace(
			$table,
			array(
				'config_key'   => self::CONFIG_FIRST_GREETING_DONE,
				'config_value' => '1',
			)
		);

		$userId = \get_current_user_id();
		if ( $userId > 0 ) {
			\delete_transient( self::TRANSIENT_PREFIX . $userId );
		}
	}

	/**
	 * Detect transition from no provider → provider and queue first greeting.
	 */
	/**
	 * Detect provider saves via the Connectors REST settings API (no reload).
	 *
	 * @param \WP_REST_Response           $response Response object.
	 * @param \WP_REST_Server             $server   Server instance.
	 * @param \WP_REST_Request            $request  Request object.
	 * @return \WP_REST_Response
	 */
	public function trackProviderOnSettingsSave( $response, $server, $request ) {
		if ( ! $request instanceof \WP_REST_Request || ! \current_user_can( 'manage_options' ) ) {
			return $response;
		}

		if ( '/wp/v2/settings' !== $request->get_route() ) {
			return $response;
		}

		if ( ! \in_array( $request->get_method(), array( 'POST', 'PUT', 'PATCH' ), true ) ) {
			return $response;
		}

		$this->trackProviderTransition( true );

		return $response;
	}

	/**
	 * Detect transition from no provider → provider and queue first greeting.
	 *
	 * @param bool $allow_rest_context When true, skip the is_admin() guard (REST save path).
	 */
	public function trackProviderTransition( bool $allow_rest_context = false ): void {
		if ( ! $allow_rest_context && ! \is_admin() ) {
			return;
		}

		if ( ! \current_user_can( 'manage_options' ) ) {
			return;
		}

		$userId = \get_current_user_id();
		if ( $userId <= 0 ) {
			return;
		}

		$hasProvider = self::hasStoredProviderCredentials();
		$stored      = \get_user_meta( $userId, self::USER_META_HAD_PROVIDER, true );

		// First admin visit for this user: seed snapshot only (avoids false trigger on upgrade).
		if ( $stored === '' || $stored === false ) {
			\update_user_meta( $userId, self::USER_META_HAD_PROVIDER, $hasProvider ? '1' : '0' );
			if ( $hasProvider && self::isOnboardingComplete() && ! self::isFirstRealGreetingDone() ) {
				self::markFirstRealGreetingDone();
			}
			return;
		}

		$hadProvider = ( $stored === '1' ) ? '1' : '0';

		if ( $hadProvider === '0' && $hasProvider && self::isOnboardingComplete() && ! self::isFirstRealGreetingDone() ) {
			\set_transient( self::TRANSIENT_PREFIX . $userId, '1', \HOUR_IN_SECONDS );
		}

		\update_user_meta( $userId, self::USER_META_HAD_PROVIDER, $hasProvider ? '1' : '0' );
	}

	/**
	 * Whether the chat should auto-open and send the first real greeting.
	 */
	public static function shouldTriggerFirstRealGreeting(): bool {
		if ( ! self::isOnboardingComplete() || ! self::hasProviderForChat() || self::isFirstRealGreetingDone() ) {
			return false;
		}

		$userId = \get_current_user_id();
		if ( $userId <= 0 ) {
			return false;
		}

		return \get_transient( self::TRANSIENT_PREFIX . $userId ) === '1';
	}
}
