<?php

declare(strict_types=1);

namespace App\Service;

use App\Service\TenantContext;

/**
 * Central configuration for plan-based feature restrictions.
 * Reads from database first, falls back to PHP constants.
 *
 * Plan hierarchy: starter < professional < enterprise
 */
class PlanFeatureService
{
    // ========================================================================
    //  DEFAULT CONSTANTS (fallback when DB has no rows)
    // ========================================================================

    private const PLAN_LIMITS = [
        'starter' => [
            'maxUsers' => 3,
            'maxNews' => 500,
            'maxStorageMb' => 1024,
        ],
        'professional' => [
            'maxUsers' => 10,
            'maxNews' => 5000,
            'maxStorageMb' => 10240,
        ],
        'enterprise' => [
            'maxUsers' => 0,
            'maxNews' => 0,
            'maxStorageMb' => 51200,
        ],
    ];

    private const PLAN_MODULES = [
        'starter' => ['menu', 'comment', 'seo'],
        'professional' => ['menu', 'comment', 'seo', 'widget', 'advertisement', 'poll', 'theme', 'amp'],
        'enterprise' => ['menu', 'comment', 'seo', 'widget', 'advertisement', 'poll', 'theme', 'amp', 'agency', 'horoscope'],
    ];

    private const PLAN_FEATURES = [
        'starter' => [
            'basic_analytics' => true,
            'custom_domain' => false,
            'api_access' => false,
            'multi_language' => false,
            'priority_support' => false,
            'custom_theme' => false,
            'bulk_import' => false,
            'advanced_seo' => false,
        ],
        'professional' => [
            'basic_analytics' => true,
            'custom_domain' => true,
            'api_access' => true,
            'multi_language' => false,
            'priority_support' => true,
            'custom_theme' => true,
            'bulk_import' => true,
            'advanced_seo' => true,
        ],
        'enterprise' => [
            'basic_analytics' => true,
            'custom_domain' => true,
            'api_access' => true,
            'multi_language' => true,
            'priority_support' => true,
            'custom_theme' => true,
            'bulk_import' => true,
            'advanced_seo' => true,
        ],
    ];

    private const PLAN_PRICING = [
        'starter' => ['monthly' => 799, 'yearly' => 7990, 'lifetime' => 19176],
        'professional' => ['monthly' => 1999, 'yearly' => 19990, 'lifetime' => 47976],
        'enterprise' => ['monthly' => 4999, 'yearly' => 49990, 'lifetime' => 119976],
    ];

    private const CURRENCY = '₺';

    private const PLAN_WEIGHT = [
        'starter' => 1,
        'professional' => 2,
        'enterprise' => 3,
    ];

    private const PLAN_DISPLAY_NAMES = [
        'starter' => 'Starter',
        'professional' => 'Professional',
        'enterprise' => 'Enterprise',
    ];

    // ========================================================================
    //  DB Cache (per-request)
    // ========================================================================

    public function __construct(
        private readonly TenantContext $tenantContext,
    ) {}

    /**
     * No longer reads from DB. Returns empty array - uses PHP constants as fallback.
     * Plan data comes from cached license API response via TenantContext.
     */
    private function getConfigurations(): array
    {
        return [];
    }

    private function getConfig(string $plan): ?object
    {
        return null;
    }

    // ========================================================================
    //  LIMITS
    // ========================================================================

    /**
     * @return array{maxUsers: int, maxNews: int, maxStorageMb: int}
     */
    public function getDefaultLimits(string $plan): array
    {
        $config = $this->getConfig($plan);
        if ($config) {
            return $config->getLimitsArray();
        }

        return self::PLAN_LIMITS[$plan] ?? self::PLAN_LIMITS['starter'];
    }

    /**
     * @return array<string, array{maxUsers: int, maxNews: int, maxStorageMb: int}>
     */
    public function getAllPlanLimits(): array
    {
        $configs = $this->getConfigurations();
        if (!empty($configs)) {
            $result = [];
            foreach (['starter', 'professional', 'enterprise'] as $plan) {
                $result[$plan] = isset($configs[$plan])
                    ? $configs[$plan]->getLimitsArray()
                    : (self::PLAN_LIMITS[$plan] ?? self::PLAN_LIMITS['starter']);
            }
            return $result;
        }

        return self::PLAN_LIMITS;
    }

    // ========================================================================
    //  MODULES
    // ========================================================================

    /** @return string[] */
    public function getAllowedModules(string $plan): array
    {
        $config = $this->getConfig($plan);
        if ($config) {
            return $config->getModules();
        }

        return self::PLAN_MODULES[$plan] ?? self::PLAN_MODULES['starter'];
    }

    public function isModuleAllowed(string $moduleSlug, string $tenantPlan): bool
    {
        return in_array($moduleSlug, $this->getAllowedModules($tenantPlan), true);
    }

    public function isPlanSufficient(string $tenantPlan, string $requiredPlan): bool
    {
        $configs = $this->getConfigurations();

        if (!empty($configs)) {
            $tenantWeight = isset($configs[$tenantPlan]) ? $configs[$tenantPlan]->getWeight() : 0;
            $requiredWeight = isset($configs[$requiredPlan]) ? $configs[$requiredPlan]->getWeight() : 0;
            return $tenantWeight >= $requiredWeight;
        }

        $tenantWeight = self::PLAN_WEIGHT[$tenantPlan] ?? 0;
        $requiredWeight = self::PLAN_WEIGHT[$requiredPlan] ?? 0;

        return $tenantWeight >= $requiredWeight;
    }

    public function getRequiredPlanForModule(string $moduleSlug): string
    {
        $configs = $this->getConfigurations();

        if (!empty($configs)) {
            foreach (['starter', 'professional', 'enterprise'] as $plan) {
                if (isset($configs[$plan]) && $configs[$plan]->hasModule($moduleSlug)) {
                    return $plan;
                }
            }
            return 'enterprise';
        }

        foreach (['starter', 'professional', 'enterprise'] as $plan) {
            if (in_array($moduleSlug, self::PLAN_MODULES[$plan], true)) {
                return $plan;
            }
        }

        return 'enterprise';
    }

    /**
     * Get all modules for all plans.
     * @return array<string, string[]>
     */
    public function getAllPlanModules(): array
    {
        $configs = $this->getConfigurations();
        if (!empty($configs)) {
            $result = [];
            foreach (['starter', 'professional', 'enterprise'] as $plan) {
                $result[$plan] = isset($configs[$plan])
                    ? $configs[$plan]->getModules()
                    : (self::PLAN_MODULES[$plan] ?? []);
            }
            return $result;
        }

        return self::PLAN_MODULES;
    }

    // ========================================================================
    //  FEATURES
    // ========================================================================

    public function isFeatureAvailable(string $feature, string $plan): bool
    {
        $config = $this->getConfig($plan);
        if ($config) {
            return $config->isFeatureEnabled($feature);
        }

        $features = self::PLAN_FEATURES[$plan] ?? self::PLAN_FEATURES['starter'];
        return $features[$feature] ?? false;
    }

    /** @return array<string, bool> */
    public function getPlanFeatures(string $plan): array
    {
        $config = $this->getConfig($plan);
        if ($config) {
            return $config->getFeatures();
        }

        return self::PLAN_FEATURES[$plan] ?? self::PLAN_FEATURES['starter'];
    }

    /**
     * Get all features for all plans.
     * @return array<string, array<string, bool>>
     */
    public function getAllPlanFeatures(): array
    {
        $configs = $this->getConfigurations();
        if (!empty($configs)) {
            $result = [];
            foreach (['starter', 'professional', 'enterprise'] as $plan) {
                $result[$plan] = isset($configs[$plan])
                    ? $configs[$plan]->getFeatures()
                    : (self::PLAN_FEATURES[$plan] ?? []);
            }
            return $result;
        }

        return self::PLAN_FEATURES;
    }

    /** @return array<string, string> */
    public function getFeatureLabels(): array
    {
        return [
            'basic_analytics' => 'Temel Analitik',
            'custom_domain' => 'Özel Domain',
            'api_access' => 'API Erişimi',
            'multi_language' => 'Çoklu Dil Desteği',
            'priority_support' => 'Öncelikli Destek',
            'custom_theme' => 'Özel Tema Yükleme',
            'bulk_import' => 'Toplu İçerik Aktarımı',
            'advanced_seo' => 'Gelişmiş SEO Araçları',
        ];
    }

    // ========================================================================
    //  PLAN INFO
    // ========================================================================

    public function getPlanDisplayName(string $plan): string
    {
        $config = $this->getConfig($plan);
        if ($config) {
            return $config->getDisplayName();
        }

        return self::PLAN_DISPLAY_NAMES[$plan] ?? ucfirst($plan);
    }

    /** @return string[] */
    public function getAvailablePlans(): array
    {
        return ['starter', 'professional', 'enterprise'];
    }

    /**
     * Whether DB configurations exist.
     */
    public function hasDbConfigurations(): bool
    {
        return !empty($this->getConfigurations());
    }

    // ========================================================================
    //  PRICING
    // ========================================================================

    public function getPrice(string $plan, string $type): int
    {
        $config = $this->getConfig($plan);
        if ($config) {
            return match ($type) {
                'monthly' => $config->getPriceMonthly(),
                'yearly' => $config->getPriceYearly(),
                'lifetime' => $config->getPriceLifetime(),
                default => $config->getPriceMonthly(),
            };
        }

        return self::PLAN_PRICING[$plan][$type] ?? self::PLAN_PRICING['starter']['monthly'];
    }

    public function getMonthlyEquivalent(string $plan, string $type): int
    {
        $price = $this->getPrice($plan, $type);

        return match ($type) {
            'yearly' => (int) round($price / 12),
            'lifetime' => (int) round($price / 24),
            default => $price,
        };
    }

    public function getYearlyDiscount(string $plan): int
    {
        $monthly = $this->getPrice($plan, 'monthly');
        $yearly = $this->getPrice($plan, 'yearly');

        if ($monthly === 0) {
            return 0;
        }

        $fullYearlyPrice = $monthly * 12;
        return (int) round((1 - ($yearly / $fullYearlyPrice)) * 100);
    }

    /** @return array{monthly: int, yearly: int, lifetime: int} */
    public function getPlanPricing(string $plan): array
    {
        $config = $this->getConfig($plan);
        if ($config) {
            return $config->getPricingArray();
        }

        return self::PLAN_PRICING[$plan] ?? self::PLAN_PRICING['starter'];
    }

    /** @return array<string, array{monthly: int, yearly: int, lifetime: int}> */
    public function getAllPlanPricing(): array
    {
        $configs = $this->getConfigurations();
        if (!empty($configs)) {
            $result = [];
            foreach (['starter', 'professional', 'enterprise'] as $plan) {
                $result[$plan] = isset($configs[$plan])
                    ? $configs[$plan]->getPricingArray()
                    : (self::PLAN_PRICING[$plan] ?? self::PLAN_PRICING['starter']);
            }
            return $result;
        }

        return self::PLAN_PRICING;
    }

    public function getCurrency(): string
    {
        return self::CURRENCY;
    }

    public function formatPrice(int $price): string
    {
        return number_format($price, 0, ',', '.') . ' ' . self::CURRENCY;
    }

    /**
     * @param array<array{type: string, plan: string, count: int}> $licenseBreakdown
     */
    public function calculateMonthlyRevenue(array $licenseBreakdown): int
    {
        $total = 0;

        foreach ($licenseBreakdown as $item) {
            $monthlyEquivalent = $this->getMonthlyEquivalent($item['plan'], $item['type']);
            $total += $monthlyEquivalent * (int) $item['count'];
        }

        return $total;
    }

    // ========================================================================
    //  SEED DEFAULTS TO DATABASE
    // ========================================================================

    /**
     * Seed all plan configurations from PHP constants into the database.
     * Skips plans that already exist.
     *
     * @return int Number of plans seeded
     */
    public function seedDefaults(): int
    {
        $repo = $this->entityManager->getRepository(PlanConfiguration::class);
        $count = 0;

        foreach (['starter', 'professional', 'enterprise'] as $plan) {
            $existing = $repo->findOneBy(['plan' => $plan]);
            if ($existing) {
                continue;
            }

            $config = new PlanConfiguration();
            $config->setPlan($plan);
            $config->setDisplayName(self::PLAN_DISPLAY_NAMES[$plan] ?? ucfirst($plan));
            $config->setWeight(self::PLAN_WEIGHT[$plan] ?? 1);

            $limits = self::PLAN_LIMITS[$plan] ?? self::PLAN_LIMITS['starter'];
            $config->setMaxUsers($limits['maxUsers']);
            $config->setMaxNews($limits['maxNews']);
            $config->setMaxStorageMb($limits['maxStorageMb']);

            $pricing = self::PLAN_PRICING[$plan] ?? self::PLAN_PRICING['starter'];
            $config->setPriceMonthly($pricing['monthly']);
            $config->setPriceYearly($pricing['yearly']);
            $config->setPriceLifetime($pricing['lifetime']);

            $config->setModules(self::PLAN_MODULES[$plan] ?? []);
            $config->setFeatures(self::PLAN_FEATURES[$plan] ?? []);

            $this->entityManager->persist($config);
            $count++;
        }

        if ($count > 0) {
            $this->entityManager->flush();
            $this->cachedConfigs = null; // Invalidate cache
        }

        return $count;
    }

    /**
     * Get default data from PHP constants (for display when no DB rows).
     */
    public function getDefaultConfigurationData(string $plan): array
    {
        return [
            'plan' => $plan,
            'displayName' => self::PLAN_DISPLAY_NAMES[$plan] ?? ucfirst($plan),
            'weight' => self::PLAN_WEIGHT[$plan] ?? 1,
            'limits' => self::PLAN_LIMITS[$plan] ?? self::PLAN_LIMITS['starter'],
            'pricing' => self::PLAN_PRICING[$plan] ?? self::PLAN_PRICING['starter'],
            'modules' => self::PLAN_MODULES[$plan] ?? [],
            'features' => self::PLAN_FEATURES[$plan] ?? [],
        ];
    }
}
