<?php

namespace App\Http\Middleware;

use App\Models\Empresa;
use App\Models\EmpresaModuloOverride;
use App\Models\ManyChatIntegracion;
use App\Models\Plan;
use App\Models\PlanModulo;
use App\Models\Suscripcion;
use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\RateLimiter;
use Symfony\Component\HttpFoundation\Response;

class ValidateManyChatToken
{
    private const RATE_LIMIT = 60;  // requests per minute per empresa

    public function handle(Request $request, Closure $next): Response
    {
        $token = $this->extractToken($request);

        if ($token === null) {
            return $this->error('Token de autorización requerido. Usa: Authorization: Bearer TU_TOKEN', 401);
        }

        $integracion = $this->resolveIntegracion($token);

        if ($integracion === null) {
            return $this->error('Token inválido o no encontrado.', 401);
        }

        if (! $integracion->activo) {
            return $this->error('La integración ManyChat está desactivada para esta empresa.', 403);
        }

        $empresa = $integracion->empresa;

        if (! $empresa || ! in_array((string) $empresa->estado, ['activa', 'activo'], true)) {
            return $this->error('La empresa asociada a este token no está activa.', 403);
        }

        if (! $this->planAllowsManyChat($empresa->id)) {
            return $this->error('El plan actual no incluye la integración ManyChat. Actualiza tu plan para usarla.', 402);
        }

        if (! $this->checkRateLimit($integracion->empresa_id)) {
            return $this->error('Límite de solicitudes excedido. Máximo '.self::RATE_LIMIT.' por minuto por empresa.', 429);
        }

        $request->attributes->set('manychat_integracion', $integracion);
        $request->attributes->set('manychat_empresa_id', $integracion->empresa_id);

        $integracion->touchConexion();

        return $next($request);
    }

    private function extractToken(Request $request): ?string
    {
        $header = $request->header('Authorization', '');
        if (str_starts_with($header, 'Bearer ')) {
            $token = trim(substr($header, 7));
            return $token !== '' ? $token : null;
        }
        // Also allow ?token= for testing in browser
        $queryToken = (string) $request->query('token', '');
        return $queryToken !== '' ? $queryToken : null;
    }

    private function resolveIntegracion(string $token): ?ManyChatIntegracion
    {
        // Cache token lookups for 5 min to reduce DB load
        return Cache::remember('mc_token_'.hash('sha256', $token), 300, function () use ($token): ?ManyChatIntegracion {
            return ManyChatIntegracion::query()
                ->with('empresa')
                ->where('api_token', $token)
                ->first();
        });
    }

    private function planAllowsManyChat(int $empresaId): bool
    {
        $override = EmpresaModuloOverride::query()
            ->where('empresa_id', $empresaId)
            ->where('modulo', 'manychat')
            ->first();

        if ($override !== null) {
            return (bool) $override->habilitado;
        }

        $suscripcion = Suscripcion::query()
            ->where('empresa_id', $empresaId)
            ->whereIn('estado', ['activa', 'morosa'])
            ->with('plan.modulos')
            ->orderByDesc('id')
            ->first();

        if ($suscripcion && $suscripcion->plan) {
            return $suscripcion->plan->tieneModulo('manychat')
                || PlanModulo::query()
                    ->where('plan_id', $suscripcion->plan->id)
                    ->where('modulo', 'manychat')
                    ->exists();
        }

        // Fallback: lowest active plan — if it allows manychat, grant access
        $plan = Plan::query()->with('modulos')->where('activo', 1)->orderBy('precio_mensual')->first();
        return $plan ? $plan->tieneModulo('manychat') : false;
    }

    private function checkRateLimit(int $empresaId): bool
    {
        $key = 'mc_rl_'.$empresaId;
        return RateLimiter::attempt($key, self::RATE_LIMIT, static function (): void {}, 60);
    }

    private function error(string $message, int $status): JsonResponse
    {
        return response()->json([
            'success' => false,
            'message' => $message,
            'data' => null,
        ], $status);
    }
}
