<?php

declare(strict_types=1);

namespace FleekDash\Admin;

if (!\function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

/**
 * Redirects classic wp-admin navigation into the FleekDash shell when appropriate.
 *
 * @package FleekDash\Admin
 */
class Interceptor
{
    /** @var list<string> */
    private const EXCLUDED_REQUEST_URI_MARKERS = [
        '/wp-admin/admin-ajax.php',
        '/wp-admin/load-scripts.php',
        '/wp-admin/load-styles.php',
        '/wp-json/',
        '/wp-admin/async-upload.php',
        '/wp-admin/admin-post.php',
        '/wp-admin/admin-header.php',
        '/wp-admin/admin-footer.php',
    ];

    /**
     * Register admin_init listener for URL interception
     */
    public function bootstrap(): void
    {
        \add_action('admin_init', [$this, 'interceptAdminUrls'], 1);
    }

    /**
     * Whether the request is embedded in the FleekDash iframe chrome.
     *
     * Navigations from themes.php/plugins.php inside the iframe may carry a Referer like
     * .../wp-admin/themes.php?...fleekdash-frame=1 without page=fleekdash.
     * When Sec-Fetch-Dest is missing (some browsers, proxies, extensions), legacy detection
     * could fail and the request fell through to SPA redirects without ?fleekdash-frame,
     * breaking nonces and intermittent delete flows.
     */
    private function isInIframe(): bool
    {
        return Iframe\IframeHelpers::requestRunsInNestedBrowsingContext();
    }

    private function currentRequestUrl(): string
    {
        return Iframe\IframeHelpers::getCurrentRequestFullUrl();
    }

    private function ensureIframeHasFrameParamOrExit(): void
    {
        $requestUri = isset($_SERVER['REQUEST_URI']) ? (string) $_SERVER['REQUEST_URI'] : '';

        $skipIframeFrameRedirect = (
            (isset($_GET['fleekdash']) && Iframe\IframeHelpers::isFleekdashNativePluginsExitParam((string) $_GET['fleekdash']))
            || isset($_GET['fleekdash-frame'])
            || (isset($_GET['page']) && $_GET['page'] === 'fleekdash')
            || (defined('DOING_AJAX') && \DOING_AJAX)
            || $this->isExcludedAdminRequestUri($requestUri)
        );

        if ($skipIframeFrameRedirect) {
            return;
        }

        $redirectUrl = \add_query_arg('fleekdash-frame', '1', $this->currentRequestUrl());
        if (
            isset($_GET['protected']) && $_GET['protected'] === 'true'
            && !Iframe\IframeHelpers::shouldOmitProtectedQueryForAdminUrl($redirectUrl)
        ) {
            $redirectUrl = \add_query_arg('protected', 'true', $redirectUrl);
        }

        \wp_safe_redirect($redirectUrl);
        exit;
    }

    private function isClassicModeTemporarilyDisabled(): bool
    {
        return class_exists('\FleekDash\Core\ClassicModeHandler')
            && \FleekDash\Core\ClassicModeHandler::isTemporarilyDisabled();
    }

    private function isExcludedAdminRequestUri(string $requestUri): bool
    {
        if ($requestUri === '') {
            return false;
        }

        foreach (self::EXCLUDED_REQUEST_URI_MARKERS as $marker) {
            if (strpos($requestUri, $marker) !== false) {
                return true;
            }
        }

        return false;
    }

    private function shouldBypassAdminIntercept(): bool
    {
        $skipForShellOrAjax = isset($_GET['fleekdash-frame'])
            || defined('DOING_AJAX')
            || (isset($_GET['page']) && $_GET['page'] === 'fleekdash');
        if ($skipForShellOrAjax) {
            return true;
        }

        $requestUri = isset($_SERVER['REQUEST_URI']) ? (string) $_SERVER['REQUEST_URI'] : '';

        return $this->isExcludedAdminRequestUri($requestUri);
    }

    private function logRelativePathDebug(string $message, string $relativePath): void
    {
        if (!defined('WP_DEBUG') || !WP_DEBUG) {
            return;
        }
        \fleekdash_log_debug($message . $relativePath);
    }

    private function computeRelativeAdminPath(string $requestUri, string $wpAdminPath): string
    {
        $relativePath = '';
        if (strpos($requestUri, $wpAdminPath) !== false) {
            $relativePath = substr($requestUri, strlen($wpAdminPath));
            if (strpos($relativePath, 'wp-admin/') === 0) {
                $relativePath = substr($relativePath, strlen('wp-admin/'));
            }
            $this->logRelativePathDebug('  Path found in admin URL, relative path: ', $relativePath);

            return $relativePath;
        }

        $relativePath = $requestUri;
        if (strpos($relativePath, '/wp-admin/') !== false) {
            $parts = explode('/wp-admin/', $relativePath, 2);
            if (isset($parts[1])) {
                $relativePath = $parts[1];
            }
        }
        $this->logRelativePathDebug('  Path not in admin URL, processed path: ', $relativePath);

        return $relativePath;
    }

    /**
     * @return never returns when redirect applies
     */
    private function redirectAdminRequestToFleekdashShell(string $currentUrl): void
    {
        if (strpos($currentUrl, \admin_url()) === false) {
            return;
        }

        $requestUri = isset($_SERVER['REQUEST_URI']) ? (string) $_SERVER['REQUEST_URI'] : '';
        $wpAdminPath = (string) \parse_url(\admin_url(), PHP_URL_PATH);

        if (defined('WP_DEBUG') && WP_DEBUG) {
            \fleekdash_log_debug('FleekDash URL Debug:');
            \fleekdash_log_debug('  Request URI: ' . $requestUri);
            \fleekdash_log_debug('  WP Admin Path: ' . $wpAdminPath);
        }

        $relativePath = ltrim($this->computeRelativeAdminPath($requestUri, $wpAdminPath), '/');

        $fleekdashUrl = \add_query_arg(
            ['page' => 'fleekdash'],
            \admin_url('admin.php'),
        ) . '#/wp/' . $relativePath;

        if (defined('WP_DEBUG') && WP_DEBUG) {
            \fleekdash_log_debug('  Final FleekDash URL: ' . $fleekdashUrl);
        }

        \wp_safe_redirect($fleekdashUrl);
        exit;
    }

    /**
     * wp-admin dashboard root → FleekDash shell (iframe script or top-level redirect).
     *
     * @return bool True when no further intercept steps should run
     */
    private function handleDashboardHomePolicy(string $pagenow): bool
    {
        if (!AdminDashboardHomePolicy::isDashboardHomeRequest($pagenow)) {
            return false;
        }

        if ($this->isInIframe()) {
            $this->ensureIframeHasFrameParamOrExit();
            AdminDashboardHomePolicy::registerEmbeddedParentDashboardRedirect();

            return true;
        }

        AdminDashboardHomePolicy::redirectTopLevelToFleekdashDashboardOrExit();
    }

    /**
     * Entry point: redirect eligible admin loads into the FleekDash app shell
     */
    public function interceptAdminUrls(): void
    {
        global $pagenow;

        $requestUri = isset($_SERVER['REQUEST_URI']) ? (string) $_SERVER['REQUEST_URI'] : '';
        $skipShellWrap = $this->isClassicModeTemporarilyDisabled()
            || $this->isExcludedAdminRequestUri($requestUri)
            || $this->handleDashboardHomePolicy((string) $pagenow);

        if ($skipShellWrap) {
            return;
        }

        if ($this->isInIframe()) {
            $this->ensureIframeHasFrameParamOrExit();

            return;
        }

        if ($this->shouldBypassAdminIntercept()) {
            return;
        }

        $this->redirectAdminRequestToFleekdashShell($this->currentRequestUrl());
    }
}
