<?php

declare(strict_types=1);

namespace App\EventSubscriber;

use App\Module\Core\Service\ModuleRegistry;
use App\Service\PlanFeatureService;
use App\Service\TenantContext;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class ModuleGuardSubscriber implements EventSubscriberInterface
{
    /**
     * Maps route prefixes to their owning module slug.
     * Core and News modules are always active and not listed here.
     */
    private const ROUTE_MODULE_MAP = [
        // Widget module (admin + frontend)
        'admin_widget' => 'widget',
        'frontend_widget' => 'widget',

        // Advertisement module (admin + frontend)
        'admin_advertisement' => 'advertisement',
        'frontend_ad' => 'advertisement',

        // Agency module (admin + frontend)
        'admin_agency' => 'agency',
        'frontend_agency' => 'agency',

        // Comment module (admin + frontend)
        'admin_comment' => 'comment',
        'frontend_news_comment' => 'comment',
        'frontend_comment' => 'comment',

        // Menu module
        'admin_menu' => 'menu',

        // Poll module (admin + frontend)
        'admin_poll' => 'poll',
        'frontend_poll' => 'poll',

        // SEO module
        'admin_seo' => 'seo',
        'admin_redirect' => 'seo',

        // Theme module
        'admin_theme' => 'theme',

        // AMP module (frontend)
        'frontend_amp' => 'amp',

        // Horoscope module (admin + frontend)
        'admin_horoscope' => 'horoscope',
        'frontend_horoscope' => 'horoscope',
    ];

    /**
     * Maps route prefixes to feature slugs (non-module features).
     */
    private const ROUTE_FEATURE_MAP = [
        'admin_api' => 'api_access',
        'admin_import' => 'bulk_import',
        'admin_language' => 'multi_language',
    ];

    public function __construct(
        private readonly ModuleRegistry $moduleRegistry,
        private readonly UrlGeneratorInterface $urlGenerator,
        private readonly TenantContext $tenantContext,
        private readonly PlanFeatureService $planFeatureService,
    ) {}

    public static function getSubscribedEvents(): array
    {
        // Run after routing but early enough to block
        return [
            KernelEvents::REQUEST => ['onKernelRequest', 10],
        ];
    }

    public function onKernelRequest(RequestEvent $event): void
    {
        if (!$event->isMainRequest()) {
            return;
        }

        $request = $event->getRequest();
        $route = $request->attributes->get('_route');

        if ($route === null) {
            return;
        }

        // Skip central panel routes
        $path = $request->getPathInfo();
        if (str_starts_with($path, '/central')) {
            return;
        }

        // 1) Check module-based access
        $moduleSlug = $this->getModuleForRoute($route);

        if ($moduleSlug !== null) {
            // First check: is the module active in tenant's config?
            if (!$this->moduleRegistry->isModuleActive($moduleSlug)) {
                $this->blockAccess($event, $moduleSlug, 'module_inactive');
                return;
            }

            // Second check: is the module allowed by tenant's plan?
            if ($this->tenantContext->isResolved()) {
                $tenantPlan = $this->tenantContext->getPlan();

                if (!$this->planFeatureService->isModuleAllowed($moduleSlug, $tenantPlan)) {
                    $this->blockAccess($event, $moduleSlug, 'plan_restricted');
                    return;
                }
            }

            return;
        }

        // 2) Check feature-based access
        $feature = $this->getFeatureForRoute($route);

        if ($feature !== null && $this->tenantContext->isResolved()) {
            $tenantPlan = $this->tenantContext->getPlan();

            if (!$this->planFeatureService->isFeatureAvailable($feature, $tenantPlan)) {
                $this->blockFeatureAccess($event, $feature);
                return;
            }
        }
    }

    private function blockAccess(RequestEvent $event, string $moduleSlug, string $reason): void
    {
        $request = $event->getRequest();
        $session = $request->getSession();

        if ($session instanceof Session) {
            $module = $this->moduleRegistry->getModule($moduleSlug);
            $moduleName = $module ? $module::getModuleName() : $moduleSlug;

            if ($reason === 'plan_restricted') {
                $requiredPlan = $this->planFeatureService->getRequiredPlanForModule($moduleSlug);
                $planName = $this->planFeatureService->getPlanDisplayName($requiredPlan);
                $session->getFlashBag()->add(
                    'warning',
                    sprintf(
                        '"%s" modülü "%s" ve üzeri paketlerde kullanılabilir. Paketinizi yükseltmek için yöneticinizle iletişime geçin.',
                        $moduleName,
                        $planName
                    )
                );
            } else {
                $session->getFlashBag()->add(
                    'warning',
                    sprintf('"%s" modülü şu anda devre dışı. Modül Yönetimi sayfasından etkinleştirebilirsiniz.', $moduleName)
                );
            }
        }

        // Determine redirect target based on route context
        $route = $request->attributes->get('_route', '');
        if (str_starts_with($route, 'admin_')) {
            $redirectUrl = $this->urlGenerator->generate('admin_dashboard');
        } else {
            $redirectUrl = $this->urlGenerator->generate('frontend_home');
        }

        $event->setResponse(new RedirectResponse($redirectUrl));
    }

    private function blockFeatureAccess(RequestEvent $event, string $feature): void
    {
        $request = $event->getRequest();
        $session = $request->getSession();

        if ($session instanceof Session) {
            $featureLabels = $this->planFeatureService->getFeatureLabels();
            $featureName = $featureLabels[$feature] ?? $feature;
            $tenantPlan = $this->tenantContext->getPlan();
            $planName = $this->planFeatureService->getPlanDisplayName($tenantPlan);

            $session->getFlashBag()->add(
                'warning',
                sprintf(
                    '"%s" özelliği "%s" paketinizde kullanılamaz. Paketinizi yükseltmek için yöneticinizle iletişime geçin.',
                    $featureName,
                    $planName
                )
            );
        }

        $redirectUrl = $this->urlGenerator->generate('admin_dashboard');
        $event->setResponse(new RedirectResponse($redirectUrl));
    }

    private function getModuleForRoute(string $route): ?string
    {
        // Check exact match first, then prefix match
        foreach (self::ROUTE_MODULE_MAP as $routePrefix => $moduleSlug) {
            if ($route === $routePrefix || str_starts_with($route, $routePrefix)) {
                return $moduleSlug;
            }
        }

        return null;
    }

    private function getFeatureForRoute(string $route): ?string
    {
        foreach (self::ROUTE_FEATURE_MAP as $routePrefix => $feature) {
            if ($route === $routePrefix || str_starts_with($route, $routePrefix)) {
                return $feature;
            }
        }

        return null;
    }
}
