<?php

namespace App\Http\Middleware;

use App\Models\Attivita;
use App\Models\Dispositivo;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;

class AttivitaMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $attivitaId = $this->resolveAttivitaId($request);
        if (! $attivitaId) {
            return $this->deny($request, 'Seleziona un\'attività per continuare');
        }

        $attivita = Attivita::find($attivitaId);
        if (! $attivita) {
            return $this->deny($request, 'Attività non trovata');
        }

        if (! $attivita->is_attiva) {
            return $this->deny($request, 'L\'attività non è attiva');
        }

        $user = Auth::user();
        if (! $user) {
            return $this->deny($request, 'Utente non autenticato');
        }

        $isSuperadmin = method_exists($user, 'hasRole') && $user->hasRole('superadmin');
        $isOwner = (int) $attivita->user_id === (int) $user->id;
        $isCassaContext = $this->isCassaContextForAttivita((int) $attivita->id);

        if (! $isSuperadmin && ! $isOwner && ! $isCassaContext) {
            return $this->deny($request, 'Non autorizzato ad accedere a questa attività');
        }

        // Mantiene allineata la sessione usata da controller e DataTable.
        if ((int) session('attivita_attuale') !== (int) $attivita->id) {
            session(['attivita_attuale' => (int) $attivita->id]);
        }

        return $next($request);
    }

    private function resolveAttivitaId(Request $request): ?int
    {
        // 1) Se la route identifica un punto vendita, usa prima quello:
        // evita mismatch con una "attivita_attuale" rimasta in sessione.
        $puntoVenditaId = (int) $request->input('punto_vendita_id');
        if ($puntoVenditaId > 0) {
            $puntoVendita = Dispositivo::find($puntoVenditaId);
            if ($puntoVendita && (int) $puntoVendita->attivita_id > 0) {
                return (int) $puntoVendita->attivita_id;
            }
        }

        $candidates = [
            $request->input('attivita_id'),
            session('attivita_attuale'),
            session('attivita_id'),
        ];

        foreach ($candidates as $candidate) {
            $value = (int) $candidate;
            if ($value > 0) {
                return $value;
            }
        }

        $dispositivoId = (int) session('dispositivo_id');
        if ($dispositivoId > 0) {
            $dispositivo = Dispositivo::find($dispositivoId);
            if ($dispositivo && (int) $dispositivo->attivita_id > 0) {
                return (int) $dispositivo->attivita_id;
            }
        }

        return null;
    }

    private function isCassaContextForAttivita(int $attivitaId): bool
    {
        $dispositivoId = (int) session('dispositivo_id');
        if ($dispositivoId > 0) {
            $dispositivo = Dispositivo::find($dispositivoId);
            if ($dispositivo && (int) $dispositivo->attivita_id === $attivitaId) {
                return true;
            }
        }

        // Fallback: alcune chiamate (es. DataTable) passano solo punto_vendita_id.
        $puntoVenditaId = (int) request()->input('punto_vendita_id');
        if ($puntoVenditaId > 0) {
            $puntoVendita = Dispositivo::find($puntoVenditaId);
            if ($puntoVendita && (int) $puntoVendita->attivita_id === $attivitaId) {
                return true;
            }
        }

        return false;
    }

    private function deny(Request $request, string $message): Response
    {
        $isDataTableRequest = $request->has('draw');
        $isAjaxLike = $request->expectsJson() || $request->wantsJson() || $request->ajax() || $isDataTableRequest;

        if ($isAjaxLike) {
            return response()->json(['success' => false, 'message' => $message], 403);
        }

        // Evita redirect infinito: attivita.index è dentro lo stesso middleware.
        if ($request->routeIs('attivita.index')) {
            abort(403, $message);
        }

        return redirect()->route('attivita.index')->with('danger', $message);
    }
}
