<?php

namespace App\Services;

use App\Models\MexcoEventEntitlement;
use App\Models\MexcoEventLicense;
use App\Models\MexcoFeature;
use App\Models\MexcoPlan;
use App\Models\MexcoPlanFeature;
use App\Models\MeetupEvent;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class EntitlementService
{
    public const LEGACY_FEATURE_MAP = [
        'allow_voting' => 'booth_voting',
        'allow_floor_plan' => 'floor_plan',
    ];

    public function allows(string $eventId, string $featureCode): bool
    {
        $license = $this->licenseForEvent($eventId);
        if ($license && ! $this->licenseGrantsAccess($license)) {
            return false;
        }

        $entitlements = $this->entitlementsForEvent($eventId);

        return (bool) ($entitlements[$featureCode]['enabled'] ?? false);
    }

    public function licenseGrantsAccess(?MexcoEventLicense $license): bool
    {
        if (! $license) {
            return true;
        }

        if ($license->status !== 'active') {
            return false;
        }

        if ($license->is_trial && $license->trial_ends_at && $license->trial_ends_at->isPast()) {
            if ($license->status === 'active') {
                $license->update([
                    'status' => 'expired',
                    'suspended_at' => now(),
                ]);
            }

            return false;
        }

        if ($license->ends_at && $license->ends_at->isPast() && $license->is_trial) {
            return false;
        }

        return true;
    }

    public function limits(string $eventId): array
    {
        $license = $this->licenseForEvent($eventId);
        $plan = $license?->plan;

        if (! $plan) {
            return $this->legacyLimits();
        }

        return [
            'participants' => $plan->participant_limit,
            'sessions' => $plan->session_limit,
            'booths' => $plan->booth_limit,
            'storage_mb' => $plan->storage_limit_mb,
            'retention_days' => $plan->retention_days,
        ];
    }

    public function limit(string $eventId, string $key): ?int
    {
        return $this->limits($eventId)[$key] ?? null;
    }

    public function entitlementsForEvent(string $eventId): array
    {
        $rows = MexcoEventEntitlement::query()
            ->where('event_id', $eventId)
            ->get();

        if ($rows->isEmpty()) {
            $this->rebuildEntitlements($eventId);
            $rows = MexcoEventEntitlement::query()
                ->where('event_id', $eventId)
                ->get();
        }

        $out = [];
        foreach ($rows as $row) {
            $out[$row->feature_code] = [
                'enabled' => $row->enabled,
                'limit_value' => $row->limit_value,
                'source' => $row->source,
            ];
        }

        return $out;
    }

    public function entitlementsForApi(string $eventId): array
    {
        $map = $this->entitlementsForEvent($eventId);
        $enabled = [];
        foreach ($map as $code => $row) {
            if ($row['enabled']) {
                $enabled[$code] = true;
            }
        }

        return $enabled;
    }

    public function rebuildEntitlements(string $eventId): void
    {
        $event = MeetupEvent::query()->find($eventId);
        if (! $event) {
            return;
        }

        $license = $this->licenseForEvent($eventId);
        if (! $license) {
            $license = $this->ensureLicense($event);
        }

        $resolved = $this->resolveFromLicense($event, $license);
        $now = now();

        DB::transaction(function () use ($eventId, $resolved, $now) {
            MexcoEventEntitlement::query()->where('event_id', $eventId)->delete();

            foreach ($resolved as $featureCode => $row) {
                MexcoEventEntitlement::query()->create([
                    'event_id' => $eventId,
                    'feature_code' => $featureCode,
                    'enabled' => $row['enabled'],
                    'limit_value' => $row['limit_value'],
                    'source' => $row['source'],
                    'source_id' => $row['source_id'],
                    'resolved_at' => $now,
                ]);
            }
        });
    }

    public function ensureLicense(MeetupEvent $event, ?string $planCode = null): MexcoEventLicense
    {
        $existing = MexcoEventLicense::query()->where('event_id', $event->id)->first();
        if ($existing) {
            return $existing;
        }

        $plan = MexcoPlan::query()
            ->where('code', $planCode ?? 'pro')
            ->firstOrFail();

        return MexcoEventLicense::query()->create([
            'event_id' => $event->id,
            'plan_id' => $plan->id,
            'status' => 'active',
            'price_cents' => $plan->price_cents,
            'currency' => $plan->currency,
            'starts_at' => $event->starts_at ?? now(),
            'ends_at' => $event->ends_at,
            'activated_at' => now(),
        ]);
    }

    public function syncLegacyFlags(MeetupEvent $event): void
    {
        $this->rebuildEntitlements($event->id);
    }

    public function assignPlan(string $eventId, string $planCode): MexcoEventLicense
    {
        $event = MeetupEvent::query()->findOrFail($eventId);
        $plan = MexcoPlan::query()->where('code', $planCode)->firstOrFail();

        $license = MexcoEventLicense::query()->updateOrCreate(
            ['event_id' => $eventId],
            [
                'plan_id' => $plan->id,
                'status' => 'active',
                'price_cents' => $plan->price_cents,
                'currency' => $plan->currency,
                'activated_at' => now(),
            ]
        );

        $this->rebuildEntitlements($eventId);

        return $license->fresh(['plan']);
    }

    protected function licenseForEvent(string $eventId): ?MexcoEventLicense
    {
        return MexcoEventLicense::query()
            ->with(['plan.planFeatures.feature', 'eventAddons.addon.features'])
            ->where('event_id', $eventId)
            ->first();
    }

    protected function resolveFromLicense(MeetupEvent $event, MexcoEventLicense $license): array
    {
        $features = MexcoFeature::query()->where('is_active', true)->orderBy('sort_order')->get();
        $resolved = [];

        foreach ($features as $feature) {
            $resolved[$feature->code] = [
                'enabled' => false,
                'limit_value' => null,
                'source' => 'plan',
                'source_id' => null,
            ];
        }

        $planFeatures = MexcoPlanFeature::query()
            ->where('plan_id', $license->plan_id)
            ->where('enabled', true)
            ->with('feature')
            ->get();

        foreach ($planFeatures as $pf) {
            if (! $pf->feature) {
                continue;
            }
            $code = $pf->feature->code;
            $resolved[$code] = [
                'enabled' => true,
                'limit_value' => $pf->limit_value,
                'source' => 'plan',
                'source_id' => $pf->id,
            ];
        }

        foreach ($license->eventAddons as $eventAddon) {
            if (! $eventAddon->isActive()) {
                continue;
            }
            $addon = $eventAddon->addon;
            if (! $addon) {
                continue;
            }
            foreach ($addon->features as $feature) {
                if (! ($feature->pivot->enabled ?? true)) {
                    continue;
                }
                $code = $feature->code;
                $resolved[$code] = [
                    'enabled' => true,
                    'limit_value' => $feature->pivot->limit_value,
                    'source' => 'addon',
                    'source_id' => $eventAddon->id,
                ];
            }
        }

        foreach (self::LEGACY_FEATURE_MAP as $flag => $featureCode) {
            if ($event->{$flag} && isset($resolved[$featureCode])) {
                $resolved[$featureCode] = [
                    'enabled' => true,
                    'limit_value' => $resolved[$featureCode]['limit_value'],
                    'source' => 'legacy',
                    'source_id' => null,
                ];
            }
        }

        return $resolved;
    }

    protected function legacyLimits(): array
    {
        return [
            'participants' => null,
            'sessions' => null,
            'booths' => null,
            'storage_mb' => null,
            'retention_days' => null,
        ];
    }

    public function planOptions(): Collection
    {
        return MexcoPlan::query()
            ->where('is_active', true)
            ->orderBy('sort_order')
            ->get();
    }
}
