<?php
/**
 * Migration Manager Class
 *
 * Coordinates the WordPress site migration process by managing export and import operations.
 *
 * @category WordPress
 * @package  Lcmigrator\LcMigrator\Migrator
 * @author   LC Team <support@leadconnectorhq.com>
 * @license  https://www.gnu.org/licenses/gpl-2.0.html GPL-2.0
 * @link     https://www.leadconnectorhq.com/
 * @since    1.0.0
 */

namespace Lcmigrator\LcMigrator\Migrator;

use Exception;
use Lcmigrator\LcMigrator\Logger\Logger;
use Lcmigrator\LcMigrator\Migrator\Export\ExportManager;
use Lcmigrator\LcMigrator\Migrator\Import\ImportManager;
use Lcmigrator\LcMigrator\Migrator\BackupInProgress\BackupInProgress;
use Lcmigrator\LcMigrator\Event\EventUpdater;

/**
 * Class MigrationManager
 *
 * Manages the complete WordPress site migration process
 *
 * @category WordPress
 * @package  Lcmigrator\LcMigrator\Migrator
 * @author   LC Team <support@leadconnectorhq.com>
 * @license  https://www.gnu.org/licenses/gpl-2.0.html GPL-2.0
 * @link     https://www.leadconnectorhq.com/
 * @since    1.0.0
 */
class MigrationManager
{
    /**
     * Logger instance
     *
     * @var Logger
     */
    private $_logger;

    /**
     * Backup directory path
     *
     * @var string
     */
    private $_backup_dir;

    /**
     * Temporary directory path
     *
     * @var string
     */
    private $_temp_dir;

    /**
     * Backup ID
     *
     * @var string
     */
    private $_backup_id;

    /**
     * BackupInProgress instance
     *
     * @var BackupInProgress
     */
    private $_backupInProgress;

    /**
     * Memory limit for the migration process in MB
     *
     * @var int
     */
    private $_memory_limit = 256;

    /**
     * MigrationManager constructor.
     *
     * @param string           $backup_dir       Directory for storing backups
     * @param string           $temp_dir         Temporary directory for processing
     * @param string           $backup_id        Unique identifier for the backup
     * @param Logger           $logger           Logger instance
     * @param BackupInProgress $backupInProgress BackupInProgress instance
     */
    public function __construct($backup_dir, $temp_dir, $backup_id, Logger $logger, BackupInProgress $backupInProgress)
    {
        $this->_backup_dir = $backup_dir;
        $this->_temp_dir = $temp_dir;
        $this->_backup_id = $backup_id;
        $this->_logger = $logger;
        $this->_backupInProgress = $backupInProgress;
        
        // Set optimal memory limit for migration
        $this->_setMemoryLimit();
    }

    /**
     * Set optimal memory limit for migration process
     *
     * @return void
     */
    private function _setMemoryLimit()
    {
        $current_limit = ini_get('memory_limit');
        $current_limit_mb = intval($current_limit);
        
        if ($current_limit_mb < $this->_memory_limit) {
            ini_set('memory_limit', $this->_memory_limit . 'M');
        }
        
        // Enable garbage collection
        gc_enable();
    }

    /**
     * Clean up memory after major operations
     *
     * @return void
     */
    private function _cleanupMemory()
    {
        gc_collect_cycles();
        
        if (function_exists('opcache_reset')) {
            opcache_reset();
        }
    }

    /**
     * Perform site export
     *
     * @return array Success status and backup details or error message
     */
    public function exportSite()
    {
        try {
            $this->_logger->info("Starting site export process");

            $export_manager = new ExportManager(
                $this->_backup_dir,
                $this->_backup_id,
                $this->_logger,
                $this->_backupInProgress
            );

            // Initialize export
            $this->updateProgress('Verifying credentials and connecting to your source website...', 1, 'running', 'Checking Connection');
            if ($this->_checkIfBackupIsStopped()) {
                return [
                    'success' => false,
                    'error' => 'Backup is stopped'
                ];
            }
            $init_result = $export_manager->initializeExport();
            if (!$init_result['success']) {
                throw new Exception($init_result['error']);
            }
            $this->_cleanupMemory();

            // Export database
            $this->updateProgress('Migrating your WordPress database...', 2, 'running', 'Exporting Database');
            if ($this->_checkIfBackupIsStopped()) {
                return [
                    'success' => false,
                    'error' => 'Backup is stopped'
                ];
            }
            // Send Pendo Event for database export started
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_DATABASE_EXPORT_STARTED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send();
            if (!$export_manager->exportDatabase()) {
                // Send Pendo Event for database export failed
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_DATABASE_EXPORT_FAILED', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $this->_backup_id,
                    'step' => 2
                ]);
                $event->send();
                throw new Exception("Failed to export database");
            }
            // Send Pendo Event for database export completed
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_DATABASE_EXPORT_COMPLETED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send();
            $this->_cleanupMemory();

            // Send Pendo Event for WordPress core export started
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_WORDPRESS_CORE_EXPORT_STARTED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send();
            $this->updateProgress('Adding WordPress configuration files...', 2, 'running', 'Exporting WordPress Core');
            // Export WordPress core
            if ($this->_checkIfBackupIsStopped()) {
                return [
                    'success' => false,
                    'error' => 'Backup is stopped'
                ];
            }
            if (!$export_manager->exportWordPressCore()) {
                // Send Pendo Event for WordPress core export failed
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_WORDPRESS_CORE_EXPORT_FAILED', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $this->_backup_id,
                    'step' => 2
                ]);
                $event->send();
                throw new Exception("Failed to export WordPress core files");
            }
            // Send Pendo Event for WordPress core export completed
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_WORDPRESS_CORE_EXPORT_COMPLETED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send();
            $this->_cleanupMemory();

            // Export configuration
            $this->updateProgress('Exporting site configuration...', 2, 'running', 'Exporting Site Configuration');
            if ($this->_checkIfBackupIsStopped()) {
                return [
                    'success' => false,
                    'error' => 'Backup is stopped'
                ];
            }
            // Send Pendo Event for site configuration export started
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_SITE_CONFIGURATION_EXPORT_STARTED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send(); 
            if (!$export_manager->exportSiteConfig()) {
                // Send Pendo Event for site configuration export failed
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_SITE_CONFIGURATION_EXPORT_FAILED', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $this->_backup_id,
                    'step' => 2
                ]);
                $event->send();
                throw new Exception("Failed to export site configuration");
            }
            // Send Pendo Event for site configuration export completed
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_SITE_CONFIGURATION_EXPORT_COMPLETED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send();
            $this->_cleanupMemory();

            // Finalize export
            $this->updateProgress('Creating a secure backup of your current website...', 3, 'running', 'Finalizing Export');
            if ($this->_checkIfBackupIsStopped()) {
                return [
                    'success' => false,
                    'error' => 'Backup is stopped'
                ];
            }
            // Send Pendo Event for finalize export started
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FINALIZE_EXPORT_STARTED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send();
            $finalize_result = $export_manager->finalizeExport();   
            if (!$finalize_result['success']) {
                // Send Pendo Event for finalize export failed
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FINALIZE_EXPORT_FAILED', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $this->_backup_id,
                    'step' => 2
                ]);
                $event->send();
                throw new Exception($finalize_result['error']);
            }
            // Send Pendo Event for finalize export completed
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FINALIZE_EXPORT_COMPLETED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send();
            $this->_backupInProgress->setMetadata('status', 'completed');
            $this->_backupInProgress->setMetadata('move_to_next', true);
            $this->_logger->info("Sending export Result ");
            // Send Pendo Event for export completed
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_EXPORT_COMPLETED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]); 
            $event->send();
            // Final memory cleanup
            $this->_cleanupMemory();
            
            return [
                'success' => true,
                'backup_path' => $init_result['backup_path'],
                'message' => 'Site exported successfully'
            ];
        } catch (Exception $e) {
            // Send Pendo Event for export failed
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_EXPORT_FAILED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $this->_backup_id,
                'step' => 2
            ]);
            $event->send();
            $this->_logger->error("Site export failed: " . $e->getMessage());
            $this->_cleanupMemory();
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Update the progress of the migration process
     *
     * @param string $message The progress message
     * @param int    $stage   The current stage number
     * @param string $status  The current status
     * @param string $action  The current action being performed
     *
     * @return void
     */
    public function updateProgress($message, $stage, $status, $action)
    {
        $this->_backupInProgress->setMetadata('message', $message);
        $this->_backupInProgress->setMetadata('stage', $stage);
        $this->_backupInProgress->setMetadata('status', $status);
        $this->_backupInProgress->setMetadata('action', $action);
    }

    /**
     * Check if the backup process has been stopped
     *
     * @return bool Returns true if backup is stopped, false otherwise
     */
    private function _checkIfBackupIsStopped()
    {
        if ($this->_backupInProgress->getMetadata('force_closed') === true) {
            $this->_logger->info("Backup is stopped : Force Closed");
            return true;
        }
    }

    /**
     * Verify system requirements for migration
     *
     * @return array Success status and message or error details
     */
    public function verifySystemRequirements()
    {
        try {
            // Check PHP version
            if (version_compare(PHP_VERSION, '7.4.0', '<')) {
                throw new Exception("PHP version 7.4.0 or higher is required");
            }

            // Check WordPress version
            global $wp_version;
            if (version_compare($wp_version, '5.0.0', '<')) {
                throw new Exception("WordPress version 5.0.0 or higher is required");
            }

            // Check directory permissions
            if (!is_writable($this->_backup_dir)) {
                throw new Exception("Backup directory is not writable");
            }

            if (!is_writable($this->_temp_dir)) {
                throw new Exception("Temporary directory is not writable");
            }

            // Check if required PHP extensions are loaded
            $required_extensions = ['zip', 'mysqli', 'json'];
            foreach ($required_extensions as $ext) {
                if (!extension_loaded($ext)) {
                    throw new Exception("Required PHP extension '$ext' is not loaded");
                }
            }

            // Check available memory
            $memory_limit = ini_get('memory_limit');
            $memory_limit_bytes = $this->_getMemoryInBytes($memory_limit);
            if ($memory_limit_bytes < ($this->_memory_limit * 1024 * 1024)) {
                throw new Exception("Minimum " . $this->_memory_limit . "M memory limit is required");
            }

            return [
                'success' => true,
                'message' => 'System requirements verified successfully'
            ];
        } catch (Exception $e) {
            $this->_logger->error("System requirements check failed: " . $e->getMessage());
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    public function perform_cleanup()
    {
        $this->_logger->info("Starting cleanup process");
        $this->_logger->info("Backup directory: " . $this->_backup_dir);
        lc_migrator_recursive_directory_delete($this->_backup_dir);
    }

    /**
     * Convert memory limit string to bytes
     *
     * @param string $memory_limit Memory limit string (e.g., '256M', '1G')
     *
     * @return int Memory in bytes
     */
    private function _getMemoryInBytes($memory_limit)
    {
        $memory_limit = trim($memory_limit);
        $last = strtolower($memory_limit[strlen($memory_limit)-1]);
        $value = intval($memory_limit);
        
        switch($last) {
            case 'g':
                $value *= 1024;
            case 'm':
                $value *= 1024;
            case 'k':
                $value *= 1024;
        }
        
        return $value;
    }
} 