<?php

/**
 * Settings Snapshot Manager
 *
 * Manages settings snapshots for backup and revert functionality.
 *
 * @package ProRank\SEO\Core
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core;

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


/**
 * Settings Snapshot Manager class
 */


class SettingsSnapshot {
    
    /**
     * Snapshot option prefix
     *
     * @var string
     */
    private const SNAPSHOT_PREFIX = '_prorank_settings_snapshot_';
    
    /**
     * Snapshot index option
     *
     * @var string
     */
    private const SNAPSHOT_INDEX = '_prorank_settings_snapshots';
    
    /**
     * Maximum number of snapshots to keep
     *
     * @var int
     */
    private const MAX_SNAPSHOTS = 10;
    
    /**
     * Settings Manager instance
     *
     * @var SettingsManager
     */
    private SettingsManager $settings_manager;
    
    /**
     * Constructor
     *
     * @param SettingsManager $settings_manager Settings manager instance
     */
    public function __construct(SettingsManager $settings_manager) {
        $this->settings_manager = $settings_manager;
    }
    
    /**
     * Create a new settings snapshot
     *
     * @param string|null $label Optional label for the snapshot
     * @return string|false Snapshot ID on success, false on failure
     */
    public function create_snapshot(?string $label = null) {
        // Check capability
        if (!current_user_can('manage_options')) {
            return false;
        }
        
        // Get current settings
        $current_settings = $this->settings_manager->get_all();
        $extra_options = $this->get_extra_options_snapshot();
        
        if (empty($current_settings) && empty($extra_options)) {
            return false;
        }
        
        // Generate timestamp-based ID
        $timestamp = current_time('timestamp');
        $snapshot_id = $timestamp . '_' . wp_generate_password(8, false);
        
        // Prepare snapshot data
        $snapshot_data = [
            'id' => $snapshot_id,
            'timestamp' => $timestamp,
            'label' => $label ?? sprintf(
                /* translators: %s: date and time */
                __('Snapshot from %1$s', 'prorank-seo'),
                wp_date('Y-m-d H:i:s', $timestamp)
            ),
            'settings' => $current_settings,
            'extra_options' => $extra_options,
            'user_id' => get_current_user_id(),
            'user_name' => wp_get_current_user()->display_name,
        ];
        
        // Save snapshot
        $snapshot_key = self::SNAPSHOT_PREFIX . $snapshot_id;
        if (!update_option($snapshot_key, $snapshot_data, false)) {
            return false;
        }
        
        // Update snapshot index
        $this->update_snapshot_index($snapshot_id, $snapshot_data);
        
        // Clean up old snapshots
        $this->cleanup_old_snapshots();
        
        return $snapshot_id;
    }
    
    /**
     * Get list of available snapshots
     *
     * @return array List of snapshots with metadata
     */
    public function list_snapshots(): array {
        $index = get_option(self::SNAPSHOT_INDEX, []);
        
        if (!is_array($index)) {
            return [];
        }
        
        // Sort by timestamp, newest first
        uasort($index, function($a, $b) {
            return ($b['timestamp'] ?? 0) <=> ($a['timestamp'] ?? 0);
        });
        
        return $index;
    }
    
    /**
     * Get a specific snapshot
     *
     * @param string $snapshot_id Snapshot ID
     * @return array|null Snapshot data or null if not found
     */
    public function get_snapshot(string $snapshot_id): ?array {
        $snapshot_key = self::SNAPSHOT_PREFIX . $snapshot_id;
        $snapshot = get_option($snapshot_key);
        
        if (!is_array($snapshot) || !isset($snapshot['settings'])) {
            return null;
        }
        
        return $snapshot;
    }
    
    /**
     * Revert to a specific snapshot
     *
     * @param string $snapshot_id Snapshot ID to revert to
     * @return bool True on success, false on failure
     */
    public function revert_to_snapshot(string $snapshot_id): bool {
        // Check capability
        if (!current_user_can('manage_options')) {
            return false;
        }
        
        // Get snapshot data
        $snapshot = $this->get_snapshot($snapshot_id);
        
        if (!$snapshot || !isset($snapshot['settings'])) {
            return false;
        }
        
        // Create a snapshot of current settings before reverting
        $this->create_snapshot(
            sprintf(
                /* translators: %s: date and time */
                __('Before revert (%1$s)', 'prorank-seo'),
                wp_date('Y-m-d H:i:s')
            )
        );
        
        // Update all settings
        $all_settings = $this->settings_manager->get_all();
        
        // Clear existing settings
        foreach (array_keys($all_settings) as $key) {
            $this->settings_manager->update($key, null);
        }
        
        // Apply snapshot settings
        foreach ($snapshot['settings'] as $key => $value) {
            $this->settings_manager->update($key, $value);
        }

        // Restore options that live outside the settings manager.
        if (!empty($snapshot['extra_options']) && is_array($snapshot['extra_options'])) {
            foreach ($snapshot['extra_options'] as $option_name => $option_value) {
                if ($option_value === null) {
                    delete_option($option_name);
                } else {
                    update_option($option_name, $option_value, false);
                }
            }
        }
        
        // Trigger action hook
        do_action('prorank_seo_settings_reverted', $snapshot_id, $snapshot);
        
        return true;
    }
    
    /**
     * Delete a specific snapshot
     *
     * @param string $snapshot_id Snapshot ID to delete
     * @return bool True on success, false on failure
     */
    public function delete_snapshot(string $snapshot_id): bool {
        // Check capability
        if (!current_user_can('manage_options')) {
            return false;
        }
        
        $snapshot_key = self::SNAPSHOT_PREFIX . $snapshot_id;
        
        // Delete the snapshot
        if (!delete_option($snapshot_key)) {
            return false;
        }
        
        // Update index
        $index = get_option(self::SNAPSHOT_INDEX, []);
        if (isset($index[$snapshot_id])) {
            unset($index[$snapshot_id]);
            update_option(self::SNAPSHOT_INDEX, $index);
        }
        
        return true;
    }
    
    /**
     * Update snapshot index
     *
     * @param string $snapshot_id Snapshot ID
     * @param array $snapshot_data Snapshot metadata
     * @return void
     */
    private function update_snapshot_index(string $snapshot_id, array $snapshot_data): void {
        $index = get_option(self::SNAPSHOT_INDEX, []);
        
        if (!is_array($index)) {
            $index = [];
        }
        
        // Add metadata to index
        $index[$snapshot_id] = [
            'id' => $snapshot_id,
            'timestamp' => $snapshot_data['timestamp'],
            'label' => $snapshot_data['label'],
            'user_id' => $snapshot_data['user_id'],
            'user_name' => $snapshot_data['user_name'],
        ];
        
        update_option(self::SNAPSHOT_INDEX, $index);
    }
    
    /**
     * Clean up old snapshots beyond the limit
     *
     * @return void
     */
    private function cleanup_old_snapshots(): void {
        $index = $this->list_snapshots();
        
        if (count($index) <= self::MAX_SNAPSHOTS) {
            return;
        }
        
        // Get IDs of snapshots to delete (oldest ones)
        $snapshot_ids = array_keys($index);
        $to_delete = array_slice($snapshot_ids, self::MAX_SNAPSHOTS);
        
        foreach ($to_delete as $snapshot_id) {
            $this->delete_snapshot($snapshot_id);
        }
    }
    
    /**
     * Clean up all snapshots (for uninstall)
     *
     * @return void
     */
    public function cleanup_all_snapshots(): void {
        global $wpdb;
        
        // Delete all snapshot options
        $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
                $wpdb->esc_like(self::SNAPSHOT_PREFIX) . '%'
            )
        );
        
        // Delete index
        delete_option(self::SNAPSHOT_INDEX);
    }

    /**
     * Capture settings that are stored outside SettingsManager.
     *
     * @return array<string, mixed>
     */
    private function get_extra_options_snapshot(): array {
        $extra_options = [];

        $option_names = [
            'prorank_seo_advanced_settings',
        ];

        foreach ($option_names as $option_name) {
            $value = get_option($option_name, null);
            if ($value !== null) {
                $extra_options[$option_name] = $value;
            }
        }

        return $extra_options;
    }
}
