<?php

namespace PloverCRM\Modules\FrontendHost;

use PloverCRM\Common\LicenseChecker;
use PloverCRM\Common\Permissions;
use PloverCRM\Core\AbstractModule;
use PloverCRM\Core\AdminMenu;
use PloverCRM\Core\Services\FrontendBootstrapBuilder;

class FrontendHostModule extends AbstractModule
{
    private const APP_ROUTE = 'plover-crm';
    private const PUBLIC_AUTH_ROUTES = ['login', 'forgot-password'];
    private const LOGOUT_ROUTE = 'logout';
    private const REWRITE_VERSION = '1';
    private const REWRITE_OPTION = 'plover_crm_frontend_host_rewrite';
    private const FRONTEND_MENU_SLUG = 'plover-crm-app';
    private const FRONTEND_MENU_CAPABILITY = 'manage_options';

    public function getId(): string
    {
        return 'frontend_host';
    }

    public function getName(): string
    {
        return 'Frontend Host';
    }

    public function getDescription(): string
    {
        return 'Hosts the standalone PloverCRM app at /plover-crm/.';
    }

    public function getMetadata(): array
    {
        return [
            'name' => 'Frontend Host',
            'description' => 'Serve the standalone PloverCRM app as a full-screen experience.',
            'version' => '1.0.0',
            'author' => 'WebPlover',
            'required' => true,
        ];
    }

    public function boot(): void
    {
        add_action('init', [$this, 'addRewriteRules']);
        add_filter('query_vars', [$this, 'addQueryVars']);
        add_action('template_redirect', [$this, 'handleRequest']);
        add_filter('redirect_canonical', [$this, 'preventAssetRedirect'], 10, 2);

        AdminMenu::addSubmenu(
            self::FRONTEND_MENU_SLUG,
            'Open PloverCRM',
            'Open CRM',
            [$this, 'renderAppMenu'],
            15,
            self::FRONTEND_MENU_CAPABILITY
        );
        add_action('admin_footer', [$this, 'injectMenuLinkScript']);

        if (get_option(self::REWRITE_OPTION) !== self::REWRITE_VERSION) {
            add_action('init', [$this, 'flushRules'], 99);
        }
    }

    public function preventAssetRedirect($redirectUrl, $requestedUrl)
    {
        if (get_query_var('plover_crm_frontend')) {
            return false;
        }

        return $redirectUrl;
    }

    public function addRewriteRules(): void
    {
        $end = chr(36);
        $baseRoute = self::APP_ROUTE;
        $catchAll = '^' . $baseRoute . '/(.+)' . $end;
        $base = '^' . $baseRoute . '/?' . $end;

        add_rewrite_rule(
            $catchAll,
            'index.php?plover_crm_frontend=1&plover_crm_frontend_path=' . $end . 'matches[1]',
            'top'
        );

        add_rewrite_rule(
            $base,
            'index.php?plover_crm_frontend=1',
            'top'
        );
    }

    public function addQueryVars(array $vars): array
    {
        $vars[] = 'plover_crm_frontend';
        $vars[] = 'plover_crm_frontend_path';

        return $vars;
    }

    public function handleRequest(): void
    {
        if (!get_query_var('plover_crm_frontend')) {
            return;
        }

        $path = ltrim((string) get_query_var('plover_crm_frontend_path', ''), '/');

        if ($this->serveStaticFile($path)) {
            return;
        }

        if ($this->isLogoutRoute($path)) {
            $this->handleLogoutRequest();
        }

        if ($this->isPublicAuthRoute($path)) {
            if ($this->currentUserHasFrontendAccess()) {
                wp_safe_redirect($this->getAppUrl());
                exit;
            }

            $this->serveSpaHtml($path, true);
        }

        $this->ensureFrontendAccess($path);
        $this->serveSpaHtml($path, false);
    }

    public function flushRules(): void
    {
        flush_rewrite_rules();
        update_option(self::REWRITE_OPTION, self::REWRITE_VERSION);
    }

    public function renderAppMenu(): void
    {
        if (!current_user_can(self::FRONTEND_MENU_CAPABILITY)) {
            wp_die(
                esc_html__('You do not have permission to open PloverCRM from the WordPress dashboard.', 'plover-crm'),
                esc_html__('PloverCRM Access Denied', 'plover-crm'),
                ['response' => 403]
            );
        }

        $url = esc_url($this->getAppUrl());

        echo '<script>window.location.replace(' . wp_json_encode($url) . ');</script>';
        echo '<div class="wrap"><p><a class="button button-primary" href="' . $url . '">Open PloverCRM</a></p></div>';
        exit;
    }

    public function injectMenuLinkScript(): void
    {
        $url = esc_url($this->getAppUrl());
        $selector = 'a[href="admin.php?page=' . esc_js(self::FRONTEND_MENU_SLUG) . '"], a[href="' . esc_js(admin_url('admin.php?page=' . self::FRONTEND_MENU_SLUG)) . '"]';

        echo '<script>(function(){document.querySelectorAll(' . wp_json_encode($selector) . ').forEach(function(link){link.href=' . wp_json_encode($url) . ';});})();</script>';
    }

    private function serveStaticFile(string $path): bool
    {
        $mimeTypes = [
            'js' => 'application/javascript',
            'css' => 'text/css',
            'json' => 'application/json',
            'png' => 'image/png',
            'jpg' => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'gif' => 'image/gif',
            'svg' => 'image/svg+xml',
            'ico' => 'image/x-icon',
            'woff' => 'font/woff',
            'woff2' => 'font/woff2',
            'ttf' => 'font/ttf',
            'eot' => 'application/vnd.ms-fontobject',
            'map' => 'application/json',
            'txt' => 'text/plain',
            'webp' => 'image/webp',
            'webmanifest' => 'application/manifest+json',
        ];

        $cleanPath = rtrim($path, '/');
        $extension = strtolower(pathinfo($cleanPath, PATHINFO_EXTENSION));

        if ($cleanPath === '' || !isset($mimeTypes[$extension])) {
            return false;
        }

        foreach ($this->getBuildDirectories() as $buildDir) {
            $baseDir = realpath($buildDir);
            if (!$baseDir) {
                continue;
            }

            $filePath = realpath($buildDir . '/' . $cleanPath);
            if (!$filePath || strpos($filePath, $baseDir) !== 0 || !is_file($filePath)) {
                continue;
            }

            if (strpos($cleanPath, '_next/') === 0) {
                header('Cache-Control: public, max-age=31536000, immutable');
            } else {
                header('Cache-Control: public, max-age=3600');
            }

            header('Content-Type: ' . $mimeTypes[$extension]);
            header('Content-Length: ' . filesize($filePath));
            readfile($filePath);
            exit;
        }

        return false;
    }

    private function serveSpaHtml(string $path, bool $public = false): void
    {
        $baseDir = $this->getPrimaryBuildDirectory();
        $baseDirResolved = $baseDir ? realpath($baseDir) : false;

        if (!$baseDir || !$baseDirResolved) {
            status_header(503);
            echo 'PloverCRM frontend build is missing.';
            exit;
        }

        $candidates = [];
        if ($path === '') {
            $candidates[] = $baseDir . '/index.html';
        } else {
            $cleanPath = rtrim($path, '/');
            $candidates[] = $baseDir . '/' . $cleanPath . '/index.html';
            $candidates[] = $baseDir . '/' . $cleanPath . '.html';
        }

        $candidates[] = $baseDir . '/404/index.html';
        $candidates[] = $baseDir . '/404.html';

        $htmlFile = null;
        foreach ($candidates as $candidate) {
            $resolved = realpath($candidate);
            if ($resolved && strpos($resolved, $baseDirResolved) === 0 && is_file($resolved)) {
                $htmlFile = $resolved;
                break;
            }
        }

        if (!$htmlFile) {
            status_header(404);
            echo 'Page not found.';
            exit;
        }

        $html = file_get_contents($htmlFile);
        $bootstrap = FrontendBootstrapBuilder::build($this->container, $public);
        $scriptTag = '<script>window.ploverCrmHost=' . wp_json_encode($bootstrap) . ';</script>';
        $html = str_replace('</head>', $scriptTag . '</head>', $html);

        if (stripos($html, 'noindex') === false) {
            $html = str_replace('</head>', '<meta name="robots" content="noindex, nofollow" /></head>', $html);
        }

        header('Content-Type: text/html; charset=utf-8');
        header('Cache-Control: no-cache');
        echo $html;
        exit;
    }

    private function ensureFrontendAccess(string $path = ''): void
    {
        if (!is_user_logged_in()) {
            wp_safe_redirect($this->buildLoginUrl($path));
            exit;
        }

        $permission = Permissions::adminPermissionCheck();

        if ($permission === true) {
            return;
        }

        if (is_wp_error($permission)) {
            $status = (int) ($permission->get_error_data()['status'] ?? 403);
            status_header($status);
            wp_die(
                esc_html($permission->get_error_message()),
                esc_html__('PloverCRM Access Denied', 'plover-crm'),
                ['response' => $status]
            );
        }

        $licenseStatus = LicenseChecker::getStatus();

        if ($licenseStatus['is_active']) {
            return;
        }

        if (current_user_can(self::FRONTEND_MENU_CAPABILITY)) {
            wp_safe_redirect((string) $licenseStatus['manage_url']);
            exit;
        }

        $this->renderLicenseRequiredPage($licenseStatus);
    }

    private function isPublicAuthRoute(string $path): bool
    {
        $firstSegment = trim(explode('/', $path, 2)[0] ?? '');

        return in_array($firstSegment, self::PUBLIC_AUTH_ROUTES, true);
    }

    private function isLogoutRoute(string $path): bool
    {
        $firstSegment = trim(explode('/', $path, 2)[0] ?? '');

        return $firstSegment === self::LOGOUT_ROUTE;
    }

    private function currentUserHasFrontendAccess(): bool
    {
        if (!is_user_logged_in()) {
            return false;
        }

        return Permissions::adminPermissionCheck() === true;
    }

    private function buildLoginUrl(string $path = ''): string
    {
        $loginUrl = home_url('/plover-crm/login/');
        $requestedUrl = $this->buildAppUrl($path);

        return add_query_arg('redirect_to', $requestedUrl, $loginUrl);
    }

    private function handleLogoutRequest(): void
    {
        if (is_user_logged_in()) {
            wp_logout();
        }

        wp_safe_redirect(add_query_arg('logged_out', '1', home_url('/plover-crm/login/')));
        exit;
    }

    private function buildAppUrl(string $path = ''): string
    {
        $normalizedPath = trim($path, '/');
        $suffix = $normalizedPath === '' ? '' : $normalizedPath . '/';

        return home_url('/plover-crm/' . $suffix);
    }

    private function renderLicenseRequiredPage(array $licenseStatus): void
    {
        $title = $licenseStatus['state'] === 'expired'
            ? __('License expired', 'plover-crm')
            : __('License required', 'plover-crm');
        $message = (string) ($licenseStatus['message'] ?? '');
        $siteName = get_bloginfo('name');
        $homeUrl = home_url('/');

        status_header(403);
        nocache_headers();
        header('Content-Type: text/html; charset=utf-8');

        echo '<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>' . esc_html($title . ' - ' . $siteName) . '</title>
    <style>
        * { box-sizing: border-box; }
        body {
            margin: 0;
            min-height: 100vh;
            display: grid;
            place-items: center;
            padding: 24px;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
            background:
                radial-gradient(circle at top, rgba(245, 158, 11, 0.18), transparent 38%),
                linear-gradient(135deg, #fffaf0 0%, #fff7ed 48%, #fffaf5 100%);
            color: #3f2501;
        }
        .card {
            width: min(100%, 560px);
            background: rgba(255, 255, 255, 0.96);
            border: 1px solid rgba(180, 83, 9, 0.12);
            border-radius: 28px;
            padding: 34px;
            box-shadow: 0 24px 64px rgba(120, 53, 15, 0.12);
        }
        .eyebrow {
            display: inline-flex;
            align-items: center;
            gap: 8px;
            padding: 8px 12px;
            border-radius: 999px;
            background: rgba(245, 158, 11, 0.12);
            color: #b45309;
            font-size: 12px;
            font-weight: 700;
            letter-spacing: 0.08em;
            text-transform: uppercase;
        }
        h1 {
            margin: 18px 0 12px;
            font-size: clamp(30px, 5vw, 40px);
            line-height: 1.05;
        }
        p {
            margin: 0;
            line-height: 1.7;
            color: #7c4a03;
        }
        .panel {
            margin-top: 24px;
            padding: 18px;
            border-radius: 20px;
            background: #fff7ed;
            border: 1px solid rgba(245, 158, 11, 0.16);
        }
        .actions {
            margin-top: 24px;
            display: flex;
            flex-wrap: wrap;
            gap: 12px;
        }
        .button {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-height: 44px;
            padding: 0 18px;
            border-radius: 999px;
            border: 1px solid rgba(120, 53, 15, 0.12);
            background: #ffffff;
            color: #7c2d12;
            text-decoration: none;
            font-weight: 600;
        }
    </style>
</head>
<body>
    <main class="card">
        <span class="eyebrow">PloverCRM</span>
        <h1>' . esc_html($title) . '</h1>
        <p>' . esc_html($message) . '</p>
        <div class="panel">
            <p>' . esc_html__('This hosted CRM workspace is temporarily unavailable until the site license is active again.', 'plover-crm') . '</p>
        </div>
        <div class="actions">
            <a class="button" href="' . esc_url($homeUrl) . '">' . esc_html__('Back to website', 'plover-crm') . '</a>
        </div>
    </main>
</body>
</html>';
        exit;
    }

    private function getBuildDirectories(): array
    {
        return [
            PLOVER_CRM_PLUGIN_PATH . 'frontend-build',
        ];
    }

    private function getPrimaryBuildDirectory(): ?string
    {
        foreach ($this->getBuildDirectories() as $buildDirectory) {
            if (is_dir($buildDirectory)) {
                return $buildDirectory;
            }
        }

        return null;
    }
    private function getAppUrl(): string
    {
        return home_url('/' . self::APP_ROUTE . '/');
    }
}
