<?php
/**
 * Activator Class
 *
 * Handles plugin activation tasks.
 *
 * FIXED: This class now properly handles fresh installs vs. updates by:
 * 1. Setting db_version to '0.0.0' initially to ensure migrations run
 * 2. Letting the migrator update the db_version after migrations complete
 * 3. Creating default settings only for fresh installs
 * 4. Properly detecting legacy installations
 *
 * @since 3.0.0
 * @package DokanKits\Setup
 */

namespace DokanKits\Setup;

use DokanKits\Core\Data\DataStore;
use DokanKits\Core\Data\Models\Settings;
use DokanKits\Core\Data\Stores\SettingsDataStore;
use DokanKits\Core\Interfaces\Runnable;
use Throwable;

/**
 * Class Activator
 *
 * Handles plugin activation
 *
 * @since 3.0.0
 * @package DokanKits\Setup
 */
class Activator implements Runnable {
	/**
	 * Run the activator
	 *
	 * FIXED: Completely refactored to ensure proper migration sequence.
	 * The key changes:
	 * 1. Don't set db_version to current plugin version immediately
	 * 2. Let migrations run and update db_version when complete
	 * 3. Better detection of fresh vs. legacy installs
	 *
	 * @since 3.0.0
	 * @return void
	 * @throws Throwable If activation fails.
	 */
	public function run(): void {
		try {
			// Get installation type and system settings.
			$installation_type = $this->determine_installation_type();
			$settings          = $this->get_or_create_system_settings( $installation_type );

			// Handle fresh installation setup if needed.
			if ( 'fresh' === $installation_type['type'] ) {
				$this->handle_fresh_installation( $settings );
			}

			// Create database tables.
			$this->initialize_data_stores();

			// Update activation metadata.
			$this->update_activation_metadata( $settings );

			/**
			 * Action that fires after plugin activation
			 *
			 * @param Settings $system_settings The system settings object.
			 * @param array    $installation_type Installation type information.
			 */
			do_action( 'dokan_kits_activated', $settings, $installation_type );

		} catch ( Throwable $e ) {
			$this->handle_activation_error( $e );
		}
	}

	/**
	 * Determine the type of installation (fresh, legacy, or update).
	 *
	 * @return array Installation type information.
	 */
	private function determine_installation_type(): array {
		$settings_store = dokan_kits_get_container()->get( SettingsDataStore::class );
		$settings       = $settings_store->get_settings_by_name( 'system' );

		// Existing installation with system settings.
		if ( $settings instanceof Settings ) {
			return array(
				'type'                => 'update',
				'previous_version'    => $settings->get( 'db_version' ),
				'has_system_settings' => true,
			);
		}

		// Legacy installation (old version).
		$migrator = dokan_kits_get_container()->get( Migrator::class );
		if ( $migrator->has_migration_options() ) {
			return array(
				'type'                => 'legacy_update',
				'previous_version'    => '$legacy_version',
				'has_system_settings' => false,
			);
		}

		// Fresh installation.
		return array(
			'type'                => 'fresh',
			'previous_version'    => '0.0.0',
			'has_system_settings' => false,
		);
	}

	/**
	 * Get existing or create new system settings.
	 *
	 * @param array $installation_type Installation type information.
	 * @return Settings System settings object.
	 */
	private function get_or_create_system_settings( array $installation_type ): Settings {
		$settings_store = dokan_kits_get_container()->get( SettingsDataStore::class );
		$settings       = $settings_store->get_settings_by_name( 'system' );

		// Return existing settings if available.
		if ( $settings instanceof Settings ) {
			return $settings;
		}

		// Create new system settings.
		$settings = dokan_kits_get_container()->get( Settings::class );
		$settings->set_name( 'system' );

		// Set initial version for migrations to run.
		$initial_db_version = '0.0.0';

		// For legacy updates, preserve the old version.
		if ( 'legacy_update' === $installation_type['type'] ) {
			$initial_db_version = $installation_type['previous_version'];
		}

		// Set initial values.
		$settings->set_value(
			array(
				'db_version'            => $initial_db_version,
				'install_date'          => current_time( 'mysql' ),
				'is_active'             => true,
				'activated_version'     => DOKAN_KITS_VERSION,
				'last_activation_time'  => time(),
				'migrated_from_version' => $installation_type['previous_version'],
				'installation_type'     => $installation_type['type'],
			)
		);

		// Set default values.
		$settings->set_default(
			array(
				'db_version'   => $initial_db_version,
				'install_date' => current_time( 'mysql' ),
				'is_active'    => true,
			)
		);

		$settings->save();

		return $settings;
	}

	/**
	 * Handle fresh installation specific tasks.
	 *
	 * @param Settings $settings System settings object.
	 * @return void
	 */
	private function handle_fresh_installation( Settings $settings ): void {
		$settings->update( 'first_activation', time() );
		$settings->update( 'is_fresh_install', true );
		$settings->save();

		/**
		 * Action fired during fresh installation.
		 *
		 * @since 3.0.0
		 * @param Settings $settings System settings object.
		 */
		do_action( 'dokan_kits_fresh_install', $settings );
	}

	/**
	 * Update activation metadata without changing db_version.
	 *
	 * @param Settings $settings System settings object.
	 * @return void
	 */
	private function update_activation_metadata( Settings $settings ): void {
		$settings->update( 'is_active', true );
		$settings->update( 'activated_version', DOKAN_KITS_VERSION );
		$settings->update( 'last_activation_time', time() );
		$settings->save();
	}

	/**
	 * Initialize all data stores to create necessary tables.
	 *
	 * @since 3.0.0
	 * @return void
	 * @throws Throwable If initialization fails.
	 */
	private function initialize_data_stores(): void {
		// Get all data stores from the container.
		$data_stores = dokan_kits_get_container()->get( 'data-store-service' );

		// Initialize each data store that has an initialize method.
		foreach ( $data_stores as $data_store ) {
			if ( ! $data_store instanceof DataStore ) {
				continue;
			}

			$data_store->create_tables();
			$data_store->update_db_version();
		}

		/**
		 * Action after initializing all data stores during activation.
		 *
		 * @since 3.0.0
		 * @param array $data_stores Array of initialized data stores.
		 */
		do_action( 'dokan_kits_activation_data_stores_initialized', $data_stores );
	}

	/**
	 * Handle activation errors.
	 *
	 * @param Throwable $e Exception that occurred.
	 * @return void
	 */
	private function handle_activation_error( Throwable $e ): void {
		// Log error if logger is available.
		if ( function_exists( 'dokan_kits_logger' ) ) {
			dokan_kits_logger()->error(
				sprintf(
					'Dokan_Kits Activation Error: %s in %s on line %s',
					$e->getMessage(),
					$e->getFile(),
					$e->getLine()
				)
			);
		}

		// Show admin notice about activation failure.
		add_action(
			'admin_notices',
			static function () use ( $e ): void {
				echo '<div class="notice notice-error"><p>';
				echo '<strong>Dokan Kits Activation Failed:</strong> ';
				echo esc_html( $e->getMessage() );
				echo '</p></div>';
			}
		);
	}
}
