<?php
/**
 * Onboarding Service
 *
 * Manages plugin onboarding flow including setup completion, status tracking, and snoozing.
 *
 * @package AIPT\Api\Services
 * @since 2.4.1
 */

namespace AIPT\Api\Services;

use AIPT\Api\Claude\ClaudeClient;
use AIPT\Api\Gemini\GeminiClient;
use AIPT\Api\OpenAI\OpenAIClient;
use AIPT\Api\OpenRouter\OpenRouterClient;
use AIPT\Core\Services\WordPressRuntimeDetector;
use AIPT\Utils\ApiKeyManager;
use AIPT\Utils\Credentials\CredentialResolver;
use AIPT\Utils\Encryption;

/**
 * Onboarding Service Implementation
 *
 * Handles plugin setup wizard, onboarding status checks, and user flow management.
 *
 * @internal Used by RestEndpoints
 */
class OnboardingService {

	/**
	 * Get onboarding status
	 *
	 * Determines if onboarding popup should be shown based on API key existence,
	 * setup completion, and snooze state.
	 *
	 * Since 2.6.0: hasApiKey/shouldShow consult CredentialResolver chain (Connectors → Local).
	 * New connectorsManaged and connectorsAvailable fields added for UI consumption.
	 *
	 * @since 2.6.0
	 *
	 * @return array Onboarding state with shouldShow, isFirstTime, hasApiKey, setupCompleted,
	 *               isSnoozed, snoozeUntil, onboardingDismissed, connectorsManaged,
	 *               connectorsAvailable, hasAnyUsableKey.
	 */
	public function getStatus(): array {

		$resolver           = CredentialResolver::instance();
		$has_any_usable_key = $resolver->hasAnyConfiguredProvider();

		$setup_completed = get_option( 'aipt_setup_completed', false );

		$snooze_until = get_option( 'aipt_onboarding_snoozed_until', 0 );
		$is_snoozed   = $snooze_until > time();

		$onboarding_dismissed = get_option( 'aipt_onboarding_dismissed', false );

		$connectors_managed = array();
		foreach ( $resolver->getStatus() as $provider_id => $state ) {
			if ( ! empty( $state['isConnectorsManaged'] ) ) {
				$connectors_managed[] = $provider_id;
			}
		}

		return array(
			'shouldShow'          => ! $has_any_usable_key && ! $setup_completed && ! $is_snoozed && ! $onboarding_dismissed,
			'isFirstTime'         => ! get_option( 'aipt_first_run_completed', false ),
			'hasApiKey'           => $has_any_usable_key,
			'setupCompleted'      => $setup_completed,
			'isSnoozed'           => $is_snoozed,
			'snoozeUntil'         => $snooze_until,
			'onboardingDismissed' => (bool) $onboarding_dismissed,
			'connectorsManaged'   => $connectors_managed,
			'connectorsAvailable' => $this->supportsConnectorsApi(),
			'hasAnyUsableKey'     => $has_any_usable_key,
		);
	}

	/**
	 * Checks if the WordPress Connectors API is available.
	 *
	 * Extracted as a protected method to allow overriding in tests without
	 * depending on function_exists() state, which persists across the test
	 * process once Brain Monkey first defines the connector functions.
	 *
	 * @since 2.6.0
	 *
	 * @return bool True if Connectors API functions exist.
	 */
	protected function supportsConnectorsApi(): bool {
		return WordPressRuntimeDetector::supportsConnectorsApi();
	}

	/**
	 * Complete setup wizard
	 *
	 * Validates and saves API key, sets default model for provider, and marks setup as complete.
	 *
	 * @param array $data Setup data containing api_key and api_provider
	 * @return array|\WP_Error Success response or error
	 * @throws \Exception If validation or save operations fail
	 */
	public function completeSetup( array $data ) {
		$api_key      = isset( $data['api_key'] ) ? sanitize_text_field( $data['api_key'] ) : '';
		$api_key      = preg_replace( '/\s+/', '', $api_key ); 
		$api_provider = isset( $data['api_provider'] ) ? sanitize_text_field( $data['api_provider'] ) : 'openai';

		try {
			if ( ! current_user_can( 'manage_options' ) ) {
				return new \WP_Error(
					'rest_forbidden',
					esc_html__( 'Sorry, you are not allowed to do that.', 'ai-product-tools' ),
					array( 'status' => 401 )
				);
			}

			if ( ! in_array( $api_provider, array( 'openai', 'gemini', 'openrouter', 'claude' ), true ) ) {
				return new \WP_Error(
					'invalid_provider',
					esc_html__( 'Invalid API provider selected.', 'ai-product-tools' ),
					array( 'status' => 400 )
				);
			}

			if ( empty( $api_key ) ) {
				return new \WP_Error(
					'empty_api_key',
					esc_html__( 'API key cannot be empty. Please enter a valid API key.', 'ai-product-tools' ),
					array( 'status' => 400 )
				);
			}

		$provider_dashboards = array(
			'openai'     => 'https://platform.openai.com/api-keys',
			'gemini'     => 'https://aistudio.google.com/app/apikey',
			'openrouter' => 'https://openrouter.ai/keys',
			'claude'     => 'https://console.anthropic.com/settings/keys',
		);

		try {
				if ( $api_provider === 'gemini' ) {
					GeminiClient::validate_api_key( $api_key );
				} elseif ( $api_provider === 'openrouter' ) {
					OpenRouterClient::validate_api_key( $api_key );
				} elseif ( $api_provider === 'claude' ) {
					ClaudeClient::validate_api_key( $api_key );
				} else {
					OpenAIClient::validate_api_key( $api_key );
				}
			} catch ( \Exception $e ) {
				$error_message = $e->getMessage();

				$is_firewall_block = stripos( $error_message, 'not valid JSON' ) !== false ||
									stripos( $error_message, 'firewall' ) !== false ||
									stripos( $error_message, 'security plugin' ) !== false;

				$is_temporary_error = stripos( $error_message, 'overloaded' ) !== false ||
									stripos( $error_message, 'unavailable' ) !== false ||
									stripos( $error_message, 'capacity' ) !== false ||
									stripos( $error_message, 'rate limit' ) !== false ||
									stripos( $error_message, '429' ) !== false;

				$is_network_error = stripos( $error_message, 'network error' ) !== false ||
									stripos( $error_message, 'unreachable' ) !== false ||
									stripos( $error_message, 'cURL' ) !== false ||
									stripos( $error_message, 'connection' ) !== false;

				if ( $is_firewall_block ) {
					return new \WP_Error(
						'api_connection_error',
						\esc_html__( 'API connection blocked. This is usually caused by server firewall or security plugin restrictions. Please contact your hosting provider or check your security plugin settings.', 'ai-product-tools' ),
						array(
							'status'        => 400,
							'error_details' => $error_message,
						)
					);
				}

				if ( $is_temporary_error ) {
					return new \WP_Error(
						'temporary_error',
						\esc_html__( 'API service is temporarily unavailable. Please try again in a few moments.', 'ai-product-tools' ),
						array(
							'status'        => 503,
							'error_details' => $error_message,
						)
					);
				}

				if ( $is_network_error ) {
					return new \WP_Error(
						'network_error',
						\esc_html__( 'Network connection error. Please check your internet connection and try again.', 'ai-product-tools' ),
						array(
							'status'        => 503,
							'error_details' => $error_message,
						)
					);
				}

			$provider_lower  = strtolower( (string) $api_provider );
			$dashboard_url   = $provider_dashboards[ $provider_lower ] ?? '';
			$troubleshooting = array(
				'dashboard_url' => $dashboard_url,
				'bullets'       => array(
					__( 'Copy the key fully without leading/trailing spaces.', 'ai-product-tools' ),
					__( 'Verify the key has not been revoked or rate limited.', 'ai-product-tools' ),
					__( 'Confirm the key is the correct type (server-side API key, not a client/org ID).', 'ai-product-tools' ),
				),
			);
			$message = sprintf(
				/* translators: 1: provider name, 2: dashboard URL or empty */
				__( 'Invalid %1$s API key. Visit %2$s to verify and re-issue.', 'ai-product-tools' ),
				ucfirst( $provider_lower ),
				$dashboard_url
			);
			return new \WP_Error(
				'invalid_api_key',
				$message,
				array(
					'status'          => 400,
					'error_details'   => $error_message,
					'troubleshooting' => $troubleshooting,
				)
			);
			}

			update_option( 'aipt_api_provider', $api_provider );

			Encryption::setup_new_installation();

			$api_key_saved = false;
			if ( $api_provider === 'gemini' ) {
				$api_key_saved = ApiKeyManager::set_gemini_key( $api_key );
				if ( ! $api_key_saved ) {
					$api_key_saved = update_option( 'aipt_gemini_api_key', $api_key );
				}
				update_option( 'aipt_model', 'gemini-2.5-flash' ); 
			} elseif ( $api_provider === 'openrouter' ) {
				$api_key_saved = ApiKeyManager::set_openrouter_key( $api_key );
				if ( ! $api_key_saved ) {
					$api_key_saved = update_option( 'aipt_openrouter_api_key', $api_key );
				}
				update_option( 'aipt_model', 'openrouter/free' ); 
			} elseif ( $api_provider === 'claude' ) {
				$api_key_saved = ApiKeyManager::set_claude_key( $api_key );
				if ( ! $api_key_saved ) {
					$api_key_saved = update_option( 'aipt_claude_api_key', $api_key );
				}
				update_option( 'aipt_model', 'claude-sonnet-4-6' ); 
			} else {
				$api_key_saved = ApiKeyManager::set_openai_key( $api_key );
				if ( ! $api_key_saved ) {
					$api_key_saved = update_option( 'aipt_openai_api_key', $api_key );
				}
				update_option( 'aipt_model', 'gpt-4.1-mini' ); 
			}

			if ( ! $api_key_saved ) {

				$provider_display = ucfirst( $api_provider );
				if ( $api_provider === 'openrouter' ) {
					$provider_display = 'OpenRouter';
				} elseif ( $api_provider === 'openai' ) {
					$provider_display = 'OpenAI';
				} elseif ( $api_provider === 'gemini' ) {
					$provider_display = 'Gemini';
				} elseif ( $api_provider === 'claude' ) {
					$provider_display = 'Claude';
				}

				return new \WP_Error(
					'api_key_save_failed',
					sprintf(
						/* translators: %s: API provider name (e.g., OpenAI, Gemini, OpenRouter) */
						esc_html__( 'Failed to save %s API key. This may be due to database permissions or server configuration issues. Please try again or contact your hosting provider.', 'ai-product-tools' ),
						$provider_display
					),
					array(
						'status'          => 500,
						'provider'        => $api_provider,
						'troubleshooting' => 'Check database permissions and server configuration',
					)
				);
			}

			update_option( 'aipt_setup_completed', true, false );
			update_option( 'aipt_needs_setup', false, false );

			update_option( 'aipt_first_run_completed', true, false );

			return array(
				'success' => true,
				'message' => esc_html__( 'Setup completed successfully.', 'ai-product-tools' ),
			);
		} catch ( \Exception $e ) {
			return new \WP_Error(
				'setup_failed',
				esc_html__( 'Error completing setup: ', 'ai-product-tools' ) . esc_html( $e->getMessage() ),
				array( 'status' => 500 )
			);
		}
	}

	/**
	 * Snooze onboarding popup
	 *
	 * Sets a timestamp for 1 hour from now to temporarily hide onboarding.
	 *
	 * @return array Success response with snooze_until timestamp
	 */
	public function snooze(): array {

		$snooze_until = time() + ( 60 * 60 ); 
		update_option( 'aipt_onboarding_snoozed_until', $snooze_until, false );

		return array(
			'success'      => true,
			'message'      => 'Onboarding snoozed for 1 hour',
			'snooze_until' => $snooze_until,
		);
	}

	/**
	 * Skip setup process
	 *
	 * Marks setup as completed and dismissed without requiring API key configuration.
	 *
	 * @return array Success response
	 */
	public function skipSetup(): array {
		update_option( 'aipt_setup_completed', true, false );
		update_option( 'aipt_needs_setup', false, false );
		update_option( 'aipt_onboarding_dismissed', true, false );
		update_option( 'aipt_first_run_completed', true, false );

		return array(
			'success' => true,
			'message' => 'Setup skipped successfully',
		);
	}

	/**
	 * Valid quick start step IDs
	 *
	 * @var string[]
	 */
	private const QUICKSTART_STEPS = array( 'settings', 'api-config', 'bulk-generator', 'automation' );

	/**
	 * Get quick start guide status
	 *
	 * Returns current progress state for preloading into frontend.
	 *
	 * @return array Quick start state with completedSteps, dismissed, completed, totalSteps
	 */
	public function getQuickStartStatus(): array {
		$completed_steps = get_option( 'aipt_quickstart_completed_steps', '[]' );
		if ( is_string( $completed_steps ) ) {
			$completed_steps = json_decode( $completed_steps, true );
			if ( ! is_array( $completed_steps ) ) {
				$completed_steps = array();
			}
		}

		$is_completed = count( array_intersect( $completed_steps, self::QUICKSTART_STEPS ) ) >= count( self::QUICKSTART_STEPS );

		return array(
			'completedSteps' => array_values( $completed_steps ),
			'dismissed'      => (bool) get_option( 'aipt_quickstart_dismissed', false ),
			'completed'      => $is_completed,
			'totalSteps'     => count( self::QUICKSTART_STEPS ),
		);
	}

	/**
	 * Complete a quick start step
	 *
	 * Marks a specific step as completed. Auto-completes guide when all steps are done.
	 *
	 * @param string $step_id Step identifier to mark complete
	 * @return array|\WP_Error Updated state or error
	 */
	public function completeQuickStartStep( string $step_id ) {
		if ( ! in_array( $step_id, self::QUICKSTART_STEPS, true ) ) {
			return new \WP_Error(
				'invalid_step',
				esc_html__( 'Invalid quick start step.', 'ai-product-tools' ),
				array( 'status' => 400 )
			);
		}

		$completed_steps = get_option( 'aipt_quickstart_completed_steps', '[]' );
		if ( is_string( $completed_steps ) ) {
			$completed_steps = json_decode( $completed_steps, true );
			if ( ! is_array( $completed_steps ) ) {
				$completed_steps = array();
			}
		}

		if ( ! in_array( $step_id, $completed_steps, true ) ) {
			$completed_steps[] = $step_id;
			update_option( 'aipt_quickstart_completed_steps', wp_json_encode( array_values( $completed_steps ) ), false );
		}

		$all_done = count( array_intersect( $completed_steps, self::QUICKSTART_STEPS ) ) >= count( self::QUICKSTART_STEPS );
		if ( $all_done ) {
			update_option( 'aipt_quickstart_completed', true, false );
		}

		return $this->getQuickStartStatus();
	}

	/**
	 * Dismiss quick start guide
	 *
	 * Permanently hides the guide panel. Can be reversed via reset.
	 *
	 * @return array Updated state
	 */
	public function dismissQuickStart(): array {
		update_option( 'aipt_quickstart_dismissed', true, false );

		return $this->getQuickStartStatus();
	}

	/**
	 * Reset quick start guide
	 *
	 * Clears all progress and makes the guide visible again.
	 *
	 * @return array Reset state
	 */
	public function resetQuickStart(): array {
		update_option( 'aipt_quickstart_completed_steps', '[]', false );
		update_option( 'aipt_quickstart_dismissed', false, false );
		update_option( 'aipt_quickstart_completed', false, false );

		return $this->getQuickStartStatus();
	}
}
