<?php

namespace WPSN\Admin;

use WPSN\Core\Branding;
use WPSN\Core\Capabilities;
use WPSN\Core\Container;
use WPSN\Core\Logger;
use WPSN\Core\UndoRuns;
use WPSN\Modules\Redirects\RedirectMigrationUndoService;
use WPSN\Modules\Redirects\RedirectRepository;
use WPSN\Modules\Revisions\RevisionsInstaller;
use WPSN\Modules\Revisions\RevisionsRepository;
use WPSN\Modules\Stability\ConfigSnapshotService;
use WPSN\Modules\Stability\SnapshotRepository;

defined('ABSPATH') || exit;

/**
 * Unified "Undo runs" admin handler + optional UI.
 */
final class UndoRunsAdmin
{
    private Container $container;
    private Logger $logger;

    public function __construct(Container $container)
    {
        $this->container = $container;
        $this->logger = $container->get('logger');
    }

    public function register(): void
    {
        add_action('admin_post_wpsn_undo_run', [$this, 'handleUndoRun']);
        add_action('admin_menu', [$this, 'registerMenu']);
    }

    public function registerMenu(): void
    {
        // Tools-level access.
        add_management_page(
            __('SEO Undo Center', 'wp-seo-next'),
            __('SEO Undo Center', 'wp-seo-next'),
            Capabilities::CAP_TOOLS,
            'wpsn-undo',
            [$this, 'renderPage']
        );
    }

    public function renderPage(): void
    {
        if (!Capabilities::canManageTools()) {
            wp_die(esc_html__('You do not have permission to access this page.', 'wp-seo-next'));
        }

        $settings = $this->container->get('settings');
        $brand = $settings ? Branding::brand($settings) : '';

        echo '<div class="wrap">';
        echo '<h1>' . esc_html__('SEO Undo Center', 'wp-seo-next') . '</h1>';
        if ($brand !== '') {
            echo '<p class="description">' . esc_html(sprintf(__('Recent undoable actions for %s (imports / migrations).', 'wp-seo-next'), $brand)) . '</p>';
        } else {
            echo '<p class="description">' . esc_html__('Recent undoable actions (imports / migrations).', 'wp-seo-next') . '</p>';
        }

        if (!empty($_GET['wpsn_notice'])) {
            $notice = sanitize_key((string) wp_unslash($_GET['wpsn_notice']));
            if ($notice === 'undo_done') {
                echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__('Undo completed.', 'wp-seo-next') . '</p></div>';
            } elseif ($notice === 'undo_already') {
                echo '<div class="notice notice-info is-dismissible"><p>' . esc_html__('This action was already undone.', 'wp-seo-next') . '</p></div>';
            } elseif ($notice === 'undo_failed') {
                $msg = isset($_GET['msg']) ? sanitize_text_field((string) wp_unslash($_GET['msg'])) : '';
                echo '<div class="notice notice-error is-dismissible"><p>' . esc_html__('Undo failed.', 'wp-seo-next');
                if ($msg !== '') {
                    echo ' ' . esc_html($msg);
                }
                echo '</p></div>';
            }
        }

        $runs = UndoRuns::list(50);
        if (empty($runs)) {
            echo '<p>' . esc_html__('No undoable actions recorded yet.', 'wp-seo-next') . '</p>';
            echo '</div>';
            return;
        }

        echo '<table class="widefat striped" style="max-width: 1180px;">';
        echo '<thead><tr>';
        echo '<th>' . esc_html__('When', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('Type', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('Label', 'wp-seo-next') . '</th>';
        echo '<th>' . esc_html__('Status', 'wp-seo-next') . '</th>';
        echo '<th style="width:220px;">' . esc_html__('Action', 'wp-seo-next') . '</th>';
        echo '</tr></thead>';
        echo '<tbody>';

        foreach ($runs as $r) {
            if (!is_array($r)) {
                continue;
            }

            $id = isset($r['id']) ? (string) $r['id'] : '';
            $type = isset($r['type']) ? (string) $r['type'] : '';
            $label = isset($r['label']) ? (string) $r['label'] : '';
            $createdAt = isset($r['created_at']) ? (string) $r['created_at'] : '';
            $status = isset($r['status']) ? (string) $r['status'] : 'active';

            echo '<tr>';
            echo '<td>' . esc_html($createdAt !== '' ? $createdAt : '—') . '</td>';
            echo '<td>' . esc_html($type !== '' ? $type : '—') . '</td>';
            echo '<td>' . esc_html($label !== '' ? $label : '—') . '</td>';
            echo '<td>' . esc_html($status) . '</td>';
            echo '<td>';

            if ($id !== '' && $status !== 'undone') {
                echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="margin:0;">';
                echo '<input type="hidden" name="action" value="wpsn_undo_run">';
                echo '<input type="hidden" name="run_id" value="' . esc_attr($id) . '">';
                echo '<input type="hidden" name="return" value="' . esc_attr($this->pageUrl()) . '">';
                wp_nonce_field('wpsn_undo_run_' . $id, 'wpsn_nonce');
                echo '<button type="submit" class="button button-secondary" onclick="return confirm(' . wp_json_encode(__('Undo this action?', 'wp-seo-next')) . ');">' . esc_html__('Undo', 'wp-seo-next') . '</button>';
                echo '</form>';
            } else {
                echo '—';
            }

            echo '</td>';
            echo '</tr>';
        }

        echo '</tbody>';
        echo '</table>';

        echo '<p class="description" style="margin-top:10px;">' . esc_html__('Tip: most operations create an auto snapshot/revision. Undo uses those records to rollback.', 'wp-seo-next') . '</p>';
        echo '</div>';
    }

    public function handleUndoRun(): void
    {
        $runId = isset($_REQUEST['run_id']) ? sanitize_text_field((string) wp_unslash($_REQUEST['run_id'])) : '';
        if ($runId === '') {
            wp_safe_redirect($this->pageUrl(['wpsn_notice' => 'undo_failed', 'msg' => 'missing_run_id']));
            exit;
        }

        $run = UndoRuns::get($runId);
        if (!is_array($run)) {
            wp_safe_redirect($this->pageUrl(['wpsn_notice' => 'undo_failed', 'msg' => 'run_not_found']));
            exit;
        }

        $type = isset($run['type']) ? sanitize_key((string) $run['type']) : '';
        $status = isset($run['status']) ? sanitize_key((string) $run['status']) : 'active';

        // Permissions depend on the run type.
        if ($type === 'redirects_migration') {
            if (!Capabilities::canManageRedirects()) {
                wp_die(esc_html__('You do not have permission to undo this action.', 'wp-seo-next'));
            }
        } else {
            if (!Capabilities::canManageTools()) {
                wp_die(esc_html__('You do not have permission to undo this action.', 'wp-seo-next'));
            }
        }

        check_admin_referer('wpsn_undo_run_' . $runId, 'wpsn_nonce');

        $return = isset($_REQUEST['return']) ? (string) wp_unslash($_REQUEST['return']) : '';
        $return = is_string($return) ? $return : '';
        $return = wp_validate_redirect($return, $this->pageUrl());

        if ($status === 'undone') {
            $url = add_query_arg(['wpsn_notice' => 'undo_already'], $return);
            wp_safe_redirect($url);
            exit;
        }

        $force = !empty($_REQUEST['force']);
        $meta = isset($run['meta']) && is_array($run['meta']) ? $run['meta'] : [];

        try {
            if ($type === 'config_snapshot') {
                $snapshotId = isset($meta['snapshot_id']) ? (int) $meta['snapshot_id'] : 0;
                if ($snapshotId <= 0) {
                    throw new \RuntimeException('missing_snapshot_id');
                }

                $this->restoreConfigSnapshot($snapshotId, $runId);

                UndoRuns::update($runId, [
                    'status' => 'undone',
                    'undone_at' => gmdate('c'),
                    'result' => [
                        'snapshot_id' => $snapshotId,
                    ],
                ]);

                $url = $this->successRedirect($return, ['wpsn_notice' => 'undo_done']);
                wp_safe_redirect($url);
                exit;
            }

            if ($type === 'redirects_migration') {
                $jobId = isset($meta['job_id']) ? sanitize_text_field((string) $meta['job_id']) : '';
                if ($jobId === '') {
                    throw new \RuntimeException('missing_job_id');
                }

                $svc = new RedirectMigrationUndoService($this->redirectRepository(), $this->logger);
                $result = $svc->undoJob($jobId, (bool) $force);

                UndoRuns::update($runId, [
                    'status' => 'undone',
                    'undone_at' => gmdate('c'),
                    'result' => $result,
                ]);

                // If return URL is the Redirect Migration page, keep its native notice format.
                if (strpos($return, 'page=wpsn-redirect-migration') !== false) {
                    $url = add_query_arg([
                        'notice' => 'undo_done',
                        'deleted' => (int) ($result['deleted'] ?? 0),
                        'restored' => (int) ($result['restored'] ?? 0),
                        'skipped' => (int) ($result['skipped'] ?? 0),
                        'already' => (int) ($result['already'] ?? 0),
                    ], $return);
                    wp_safe_redirect($url);
                    exit;
                }

                $url = $this->successRedirect($return, ['wpsn_notice' => 'undo_done']);
                wp_safe_redirect($url);
                exit;
            }

            throw new \RuntimeException('unsupported_type');
        } catch (\Throwable $e) {
            $msg = $e->getMessage();
            $msg = is_string($msg) ? sanitize_key($msg) : 'error';
            $url = add_query_arg(['wpsn_notice' => 'undo_failed', 'msg' => $msg], $return);
            wp_safe_redirect($url);
            exit;
        }
    }

    private function pageUrl(array $args = []): string
    {
        $base = admin_url('tools.php?page=wpsn-undo');
        return !empty($args) ? add_query_arg($args, $base) : $base;
    }

    /**
     * Ensure we don't keep stacking notices on repeated redirects.
     */
    private function successRedirect(string $return, array $args): string
    {
        // Remove previous notices if any.
        $return = remove_query_arg(['wpsn_notice', 'msg'], $return);
        return add_query_arg($args, $return);
    }

    private function redirectRepository(): RedirectRepository
    {
        return new RedirectRepository($this->container->get('cache'), $this->logger);
    }

    private function restoreConfigSnapshot(int $snapshotId, string $runId): void
    {
        $repo = new SnapshotRepository();
        $snap = $repo->get($snapshotId);
        if (!is_array($snap) || (string) ($snap['type'] ?? '') !== SnapshotRepository::TYPE_CONFIG) {
            throw new \RuntimeException('snapshot_not_found');
        }

        $payload = isset($snap['payload_decoded']) && is_array($snap['payload_decoded']) ? $snap['payload_decoded'] : [];
        $settingsArr = ConfigSnapshotService::extractSettings($payload);
        $settingsArr = is_array($settingsArr) ? $settingsArr : [];

        // Safety: create a backup snapshot before overwrite.
        $backupId = 0;
        try {
            $backupId = ConfigSnapshotService::createAutoSnapshot(
                sprintf('Auto backup: before Undo Run restore (#%d)', (int) $snapshotId)
            );
        } catch (\Throwable $e) {
            $backupId = 0;
        }

        // Revisions entry (best-effort).
        try {
            $settings = $this->container->get('settings');
            if ($settings && $settings->moduleEnabled('revisions', true)) {
                RevisionsInstaller::maybeInstall();
                $revRepo = new RevisionsRepository($this->logger);
                $revRepo->insert([
                    'object_type' => 'config',
                    'object_id' => 1,
                    'action' => 'restore',
                    'source' => 'undo_runs',
                    'actor_user_id' => (int) get_current_user_id(),
                    'before' => ['settings' => $settings->all()],
                    'after' => ['settings' => $settingsArr],
                    'meta' => [
                        'undo_run_id' => $runId,
                        'snapshot_id' => (int) $snapshotId,
                        'backup_id' => (int) $backupId,
                    ],
                ]);
            }
        } catch (\Throwable $e) {
            // silent
        }

        update_option(SettingsRepository::OPTION_NAME, $settingsArr, false);
        $this->container->get('settings')->flush();

        do_action('wpsn/stability/config_snapshot_restored', $snapshotId, $backupId);
    }
}
